我正在运行payara微型服务器,在序列化对象时遇到一些困难。
根对象有一个子对象,其类型为A
或B 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
]]
答案 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>