自定义Jackson序列化到Json在Wildfly 26中不起作用

eanckbw9  于 2023-05-13  发布在  其他
关注(0)|答案(1)|浏览(177)

我正在尝试将一个大型复杂的项目从Wildfly 23升级到Wildfly 26,但Json响应不再返回我们期望的有效负载。以下是两个例子:

  1. Package 列表的对象应该返回 Package 列表的Json数组,但它将返回 Package 对象和列表一起,即它应该返回[ ... ],但它正在返回{ "objects": [ ... ] }
    Package 器类在列表getter方法上使用**@JsonValue**,这应该使其工作,但列表类上的自定义序列化器没有被调用。
    1.使用@JsonFormat(pattern = ...some pattern...)注解的日期字段不会被格式化。
    它是一个Java 11项目(11.0.14.1,Eclipse Adoptium),使用Maven 3.6.3创建一个部署到Wildfly 26(构建在Windows 10 Enterprise上并部署到Windows Server 2019 Standard)的WAR文件。我创建了一个非常精简的示例来说明行为(下面显示的类/文件)。
    我使用mvn clean verify构建了这个项目,它创建了target\jsontest.war,然后将其复制到standalone\deployments目录,在那里它可以成功部署。使用了一个自定义登录模块,但我不认为它与问题有关,因为正在到达端点。
    server.log中有两个警告,我认为它们不相关:
WARN  [org.jboss.as.dependency.deprecated] (MSC service thread 1-5) WFLYSRV0221: Deployment "deployment.jsontest.war" is using a deprecated module ("javax.api") which may be removed in future versions without notice.
WARN  [org.jboss.as.dependency.deprecated] (MSC service thread 1-5) WFLYSRV0221: Deployment "deployment.jsontest.war" is using a deprecated module ("org.jboss.resteasy.resteasy-jaxrs") which may be removed in future versions without notice.

任何帮助,使这一工作将不胜感激。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>jsontest</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>8.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.7.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.12.7</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>jsontest</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.2</version>
                <configuration>
                    <webResources>
                        <resource>
                            <directory>${project.basedir}/src/main/webapp</directory>
                        </resource>
                    </webResources>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

src/main/java/org/example/jsontest下有以下类:

MainResource.java

package org.example.jsontest;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;

@Path("/")
public class MainResource {

    @GET
    @Path("json")
    @Produces({ MediaType.APPLICATION_JSON })
    public Response getJsonExample() {
        // We want to return a Json array containing 2 objects
        final SomeObject object1 = new SomeObject().setA("a1").setB("b1");
        final SomeObject object2 = new SomeObject().setA("a2").setC("c2");
        final ResponseList<SomeObject> objectList = new ResponseList<>();
        objectList.addAll(List.of(object1, object2));
        final ResponseListWrapper<SomeObject> wrapper = new ResponseListWrapper<>();
        wrapper.setObjects(objectList);
        return Response.ok(wrapper).build();
    }
}

ResponseListWrapper.java

package org.example.jsontest;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonValue;

@JsonInclude(value = Include.NON_NULL)
public class ResponseListWrapper<T> {

    private ResponseList<T> objects;

    public ResponseListWrapper() {
        objects = new ResponseList<>();
    }

    public ResponseListWrapper(ResponseList<T> objects) {
        setObjects(objects);
    }

    /**
     * @JsonValue is supposed to indicate that the value from the method is to be used to produce the Json output.
     * We want to return a Json array, not the wrapped object with an array, i.e.
     *
     * [ { "a": "a1", "b": "b1" }, { "a": "a2", "c": "c2" } ]
     *
     * But instead we get the wrapped object:
     * { "objects": [ { "a": "a1", "b": "b1" }, { "a": "a2", "c": "c2" } ] }
     *
     * ResponseList is annotated with @JsonSerialize(using = JacksonListSerializer.class)
     * but JacksonListSerializer.serialize() is never called.
     *
     */
    @JsonValue
    public ResponseList<T> getObjects() {
        return objects;
    }

    public void setObjects(ResponseList<T> objects) {
        this.objects = objects;
    }
}

ResponseList.java

package org.example.jsontest;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import java.util.ArrayList;
import java.util.Collection;

/**
 *
 * @JsonSerialize is supposed to tell Jackson to use JacksonListSerializer when generating a Json response but it is not
 * being called.
 */
@JsonSerialize(using = JacksonListSerializer.class)
public class ResponseList<T> extends ArrayList<T> {

    private static final long serialVersionUID = -6120242076197274777L;

    public ResponseList() {
    }

    public ResponseList(Collection<? extends T> c) {
        super(c);
    }

    public ResponseList(int initialCapacity) {
        super(initialCapacity);
    }
}

JacksonListSerializer.java

package org.example.jsontest;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;

public class JacksonListSerializer extends JsonSerializer<ResponseList<?>> {

    @Override
    public void serialize(ResponseList<?> list, JsonGenerator generator, SerializerProvider provider)
            throws IOException {
        generator.writeStartArray();
        if (list != null) {
            for (Object item : list) {
                generator.writeObject(item);
            }
        }
        generator.writeEndArray();
    }
}

SomeObject.java

package org.example.jsontest;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;

import java.io.Serializable;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class SomeObject implements Serializable {

    private static final long serialVersionUID = 6725549179169119963L;

    private String a;
    private String b;
    private String c;

    public String getA() {
        return a;
    }

    public SomeObject setA(final String a) {
        this.a = a;
        return this;
    }

    public String getB() {
        return b;
    }

    public SomeObject setB(final String b) {
        this.b = b;
        return this;
    }

    public String getC() {
        return c;
    }

    public SomeObject setC(final String c) {
        this.c = c;
        return this;
    }
}

src/main/webapp下有以下文件:

jboss-deployment-structure.xml

<jboss-deployment-structure>
    <deployment>
        <dependencies>
            <module name="org.wildfly.security.elytron"/>
            <module name="org.wildfly.extension.elytron"/>
            <module name="javax.api"/>
            <module name="org.jboss.resteasy.resteasy-jaxrs"/>
            <module name="org.jboss.resteasy.resteasy-jackson2-provider"/>
        </dependencies>
    </deployment>
</jboss-deployment-structure>

jboss-web.xml

<?xml version="1.0"?>

<jboss-web xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.jboss.com/xml/ns/javaee"
           version="6.0"
           xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-web_6_0.xsd">

    <security-domain>...removed...</security-domain>
    <context-root>/jsontest</context-root>
</jboss-web>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <display-name>jsontest</display-name>

    <!-- Security related settings have been removed -->

    <servlet-mapping>
        <servlet-name>javax.ws.rs.core.Application</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

    <session-config>
        <session-timeout>30</session-timeout>
        <cookie-config>
            <path>/jsontest</path>
            <http-only>true</http-only>
            <secure>true</secure>
        </cookie-config>
        <tracking-mode>COOKIE</tracking-mode>
    </session-config>
</web-app>
w80xi6nr

w80xi6nr1#

终于找到了原因。我们有一个自定义的身份验证/登录模块,它使用自己的Jackson库副本(jackson-core-2.13.4.jar,jackson-databind-2.13.4.2.jar,jackson-annotations-2.13.4.jar)。我将它们从module.xml中删除,并将以下内容添加到module.xml中的依赖项中:

<module name="org.jboss.resteasy.resteasy-jaxrs"/>
<module name="org.jboss.resteasy.resteasy-jackson2-provider"/>

重启Wildfly后,有效载荷按预期返回。我确实按照James的建议使用了-D"resteasy.preferJacksonOverJsonB"="true"设置(谢谢!).

相关问题