JSON序列化跳过子元素

时间:2018-06-20 14:31:47

标签: java json java-ee jersey payara

我正在运行payara微型服务器,在序列化对象时遇到一些困难。

根对象有一个子对象,其类型为AB extends A。问题在于,它总是像序列A一样被序列化为json,即序列类型为B的属性都不会被序列化。

返回Response对象之后,我已经检查了对象是否正确。

pom.xml看起来像这样:

<build>
    <finalName>profile</finalName>

    <plugins>
        <plugin>
            <groupId>fish.payara.maven.plugins</groupId>
            <artifactId>payara-micro-maven-plugin</artifactId>
            <version>1.0.0</version>
            <executions>
                <execution>
                    <goals>
                        <goal>bundle</goal>
                        <goal>start</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <payaraVersion>4.1.2.173</payaraVersion>
                <useUberJar>true</useUberJar>
                <deployWar>false</deployWar>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

<dependencies>
    <dependency>
        <groupId>org.eclipse.microprofile</groupId>
        <artifactId>microprofile-bom</artifactId>
        <version>1.1.0</version>
        <type>pom</type>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
        <version>7.0</version>
    </dependency>
    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-json</artifactId>
        <version>1.19.4</version>
    </dependency>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>LATEST</version>
    </dependency>
    <dependency>
        <groupId>io.swagger</groupId>
        <artifactId>swagger-jaxrs</artifactId>
        <version>1.5.20</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.3.1.Final</version>
    </dependency>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>9.4.1212</version>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.0</version>
    </dependency>
</dependencies>

我当时在想,也许我应该只更改为org.glassfish.jersey.media.jersey-media-json-jackson,也许会有所帮助,但是然后我得到了这个异常HK2 failure has been detected in a code that does not run in an active Jersey Error scope.

因此,我现在不确定该怎么办。有什么方法可以配置com.sun.jersey.jersey-json解析器,还是我应该放弃它,而尝试在其中强制jersey-media-json-jackson

编辑:我已经意识到,payara默认使用MOXy json,但问题仍然相同

为了显示一些示例,我将这段代码简化一些:

public class CategoryDTO {
    private String name;
    private List<QuestionDTO> questions;
}

public class QuestionDTO {
    private String id;
}

public class QuestionAdminDTO extends QuestionDTO {
    private String comment;
}

当它被序列化时我得到

{
   "name":"some name",
   "questions":[
       {
          "id":"some id"
       }
   ]
}

但是我希望comment应该这样包含

{
   "name":"some name",
   "questions":[
       {
          "id":"some id",
          "comment":"some comment"
       }
   ]
}

经过更多测试后,如果我尝试直接封送QuestionDTO对象,则有效,但是如果它处于嵌套状态,则无效

我的应用程序配置了一个/webapp/WEB-INF/glassfish-web.xml文件,如下所示:

<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD
GlassFish Application Server 3.1 Servlet 3.0//EN"
        "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app>
    <session-config>
        <session-manager/>
    </session-config>
    <class-loader delegate="false"/>
</glassfish-web-app>

以及“自定义” Application类:

@ApplicationPath("/api")
public class RestApplication extends Application {

    public RestApplication() {
        Swagger swagger = new Swagger();
        swagger.securityDefinition("JWT_AUTHORIZATION", new ApiKeyAuthDefinition("access_token", In.HEADER));
        new SwaggerContextService().updateSwagger(swagger);

        BeanConfig beanConfig = new BeanConfig();
        beanConfig.setDescription("profile");
        beanConfig.setTitle("Profile");
        beanConfig.setVersion("1.0-SNAPSHOT");
        beanConfig.setSchemes(new String[]{"http"});
        beanConfig.setBasePath("/profile/api");
        beanConfig.setResourcePackage("se.profile");
        beanConfig.setScan(true);
    }
}

添加杰克逊时得到的stacktrace

[2018-06-21T10:37:26.526+0200] [] [WARNING] [] [org.glassfish.jersey.internal.Errors] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1529570246526] [levelValue: 900] [[
  The following warnings have been detected: WARNING: HK2 failure has been detected in a code that does not run in an active Jersey Error scope.
WARNING: Unknown HK2 failure detected:
MultiException stack 1 of 1
javax.enterprise.inject.CreationException
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at java.lang.Class.newInstance(Class.java:442)
    at org.jboss.weld.security.NewInstanceAction.run(NewInstanceAction.java:33)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.jboss.weld.injection.Exceptions.rethrowException(Exceptions.java:40)
    at org.jboss.weld.injection.Exceptions.rethrowException(Exceptions.java:50)
    at org.jboss.weld.injection.Exceptions.rethrowException(Exceptions.java:90)
    at org.jboss.weld.injection.ConstructorInjectionPoint.newInstance(ConstructorInjectionPoint.java:127)
    at org.jboss.weld.injection.ConstructorInjectionPoint.invokeAroundConstructCallbacks(ConstructorInjectionPoint.java:92)
    at org.jboss.weld.injection.ConstructorInjectionPoint.newInstance(ConstructorInjectionPoint.java:78)
    at org.jboss.weld.injection.producer.AbstractInstantiator.newInstance(AbstractInstantiator.java:28)
    at org.jboss.weld.injection.producer.BasicInjectionTarget.produce(BasicInjectionTarget.java:112)
    at org.jboss.weld.injection.producer.BeanInjectionTarget.produce(BeanInjectionTarget.java:180)
    at org.glassfish.jersey.ext.cdi1x.internal.AbstractCdiBeanHk2Factory$2.getInstance(AbstractCdiBeanHk2Factory.java:139)
    at org.glassfish.jersey.ext.cdi1x.internal.AbstractCdiBeanHk2Factory._provide(AbstractCdiBeanHk2Factory.java:91)
    at org.glassfish.jersey.ext.cdi1x.internal.GenericCdiBeanHk2Factory.provide(GenericCdiBeanHk2Factory.java:63)
    at org.jvnet.hk2.internal.FactoryCreator.create(FactoryCreator.java:153)
    at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:487)
    at org.jvnet.hk2.internal.PerLookupContext.findOrCreate(PerLookupContext.java:70)
    at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2126)
    at org.jvnet.hk2.internal.ServiceLocatorImpl.internalGetService(ServiceLocatorImpl.java:777)
    at org.jvnet.hk2.internal.ServiceLocatorImpl.internalGetService(ServiceLocatorImpl.java:740)
    at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:710)
    at org.glassfish.jersey.server.ApplicationHandler.createApplication(ApplicationHandler.java:385)
    at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:342)
    at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:392)
    at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:177)
    at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:369)
    at javax.servlet.GenericServlet.init(GenericServlet.java:244)
    at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1495)
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1294)
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5303)
    at org.apache.catalina.core.StandardContext.start(StandardContext.java:5548)
    at com.sun.enterprise.web.WebModule.start(WebModule.java:522)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:917)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:900)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:684)
    at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:2057)
    at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:1703)
    at com.sun.enterprise.web.WebApplication.start(WebApplication.java:107)
    at org.glassfish.internal.data.EngineRef.start(EngineRef.java:122)
    at org.glassfish.internal.data.ModuleInfo.start(ModuleInfo.java:294)
    at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:357)
    at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:501)
    at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:220)
    at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:488)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:544)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:540)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:360)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$2.execute(CommandRunnerImpl.java:539)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:570)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:562)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:360)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:561)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1469)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1300(CommandRunnerImpl.java:111)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1851)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1727)
    at com.sun.enterprise.admin.cli.embeddable.DeployerImpl.deploy(DeployerImpl.java:134)
    at com.sun.enterprise.admin.cli.embeddable.DeployerImpl.deploy(DeployerImpl.java:149)
    at fish.payara.micro.impl.PayaraMicroImpl.deployAll(PayaraMicroImpl.java:1377)
    at fish.payara.micro.impl.PayaraMicroImpl.bootStrap(PayaraMicroImpl.java:993)
    at fish.payara.micro.impl.PayaraMicroImpl.main(PayaraMicroImpl.java:186)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at fish.payara.micro.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
    at fish.payara.micro.boot.loader.Launcher.launch(Launcher.java:107)
    at fish.payara.micro.boot.loader.Launcher.launch(Launcher.java:70)
    at fish.payara.micro.boot.PayaraMicroLauncher.main(PayaraMicroLauncher.java:79)
    at fish.payara.micro.PayaraMicro.main(PayaraMicro.java:361)
Caused by: java.lang.NoClassDefFoundError: com/fasterxml/jackson/annotation/JsonMerge
    at com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector.<clinit>(JacksonAnnotationIntrospector.java:50)
    at com.fasterxml.jackson.databind.ObjectMapper.<clinit>(ObjectMapper.java:291)
    at io.swagger.util.ObjectMapperFactory.create(ObjectMapperFactory.java:35)
    at io.swagger.util.ObjectMapperFactory.createJson(ObjectMapperFactory.java:23)
    at io.swagger.util.ObjectMapperFactory.createJson(ObjectMapperFactory.java:19)
    at io.swagger.util.Json.mapper(Json.java:13)
    at io.swagger.jaxrs.DefaultParameterExtension.<init>(DefaultParameterExtension.java:50)
    at io.swagger.jaxrs.ext.SwaggerExtensions.<clinit>(SwaggerExtensions.java:36)
    at io.swagger.jaxrs.utils.ReaderUtils.collectParameters(ReaderUtils.java:123)
    at io.swagger.jaxrs.utils.ReaderUtils.collectFieldParameters(ReaderUtils.java:96)
    at io.swagger.jaxrs.Reader.read(Reader.java:291)
    at io.swagger.jaxrs.Reader.read(Reader.java:175)
    at io.swagger.jaxrs.config.BeanConfig.scanAndRead(BeanConfig.java:242)
    at io.swagger.jaxrs.config.BeanConfig.setScan(BeanConfig.java:221)
    at se.profile.RestApplication.<init>(RestApplication.java:30)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.jboss.weld.injection.ConstructorInjectionPoint.newInstance(ConstructorInjectionPoint.java:119)
    ... 66 more
Caused by: java.lang.ClassNotFoundException: com.fasterxml.jackson.annotation.JsonMerge
    at org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1655)
    at org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1501)
    ... 86 more

]]

1 个答案:

答案 0 :(得分:1)

最简单的解决方案是使用Jackson。 MOXy基于JAXB规则,在某些情况下(包括使用继承)可能会变得非常复杂。杰克逊只是工作。

只需添加Jackson依赖项(在提供的范围内,因为Payara已经具有依赖项)并向应用程序注册JacksonFeature

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>2.25.1</version>
    <scope>provided</scope>
</dependency>

我看不到如何配置应用程序,因此我不建议注册JacksonFeature的适当方法。如果您不知道如何执行此操作,则可以使用应用程序配置更新您的信息,也可以只搜索其注册方式。

更新

要在JacksonFeature类中注册Application,您可以使用property

public class RestAppication extends Application {

    @Override
    public Map<String, Object> getProperties() {
        Map<String, Object> props = new HashSet<>();

        String classnames = JacksonFeature.class.getName();
        props.put("jersey.config.server.provider.classnames", classnames);
        props.put("jersey.config.disableMoxyJson", true);
        return props;
    }
}

如果遇到Jackson依赖冲突,而这可能是由于使用Swagger(将Jackson拖入)而发生的,则您只需将Jackson排除在Swagger外,因为服务器应该已经具有依赖了

<dependency>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-jaxrs</artifactId>
    <version>1.5.20</version>
    <exclusions>
        <exclusion>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </exclusion>
        <exclusion>
            <groupId>com.fasterxml.jackson.module</groupId>
            <artifactId>jackson-module-jaxb-annotations</artifactId>
        <exclusion>
    </exclusions>
</dependency>
相关问题