我在将泽西岛从1.x迁移到2.x时遇到了一些问题。我的应用程序使用Jersey提供REST Web服务,通过Jackson和Spring 4以JSON方式提供数据来处理依赖注入。
在Jersey 1.xi曾经将JsonDeserializer编写为由Spring管理的组件,所以我可以在反序列化期间访问我的服务以从persistance层加载我的域对象,但在2.x中我遇到了注入问题解串器中的服务工作。我所采用的方法受到了这篇博文的启发:http://www.runningasroot.com/blog/2012/05/02/autowiring-jackson-deserializers-in-spring/
这是我的 pom.xml 的依赖部分:
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Jersey -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
<!-- Commons Codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
<!-- cut -->
<dependencies>
泽西岛版本是2.7,Spring 4.0.2.RELEASE。
这是我的 web.xml :
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<module-name>myApp/module-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>it.mgt.myApp.config.ApplicationConfig</param-value>
</context-param>
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>it.mgt.myApp.config.JerseyConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
</web-app>
这是我的 Spring配置类:
@Configuration
@ComponentScan({"it.mgt.myApp"})
@PropertySource("classpath:myApp.properties")
public class ApplicationConfig {
// Cut
}
这是我的泽西资源配置类:
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
packages("it.mgt.myApp");
register(MultiPartFeature.class);
register(RequestContextFilter.class);
register(ObjectMapperContextResolver.class);
register(JacksonFeature.class);
register(CorsRequestFilter.class);
register(SignatureProcessingFilter.class);
register(AuthorizationFeature.class);
register(CorsResponseFilter.class);
register(new UserBinder());
}
}
这是我的 ObjectMapperContextResolver 类:
@Component
@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
@Autowired
private SpringObjectMapper objectMapper;
public ObjectMapperContextResolver() {
super();
}
@Override
public ObjectMapper getContext(Class<?> type) {
return objectMapper;
}
}
我认为@Provider注释与资源配置类中的registrationg是多余的。
这是我的 SpringObjectMapper 类:
@Component
public class SpringObjectMapper extends ObjectMapper {
private static final long serialVersionUID = 1413033425692174337L;
@Autowired
ApplicationContext applicationContext;
public SpringObjectMapper() {
this.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
this.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, true);
}
@Override
@Autowired
public void setHandlerInstantiator(HandlerInstantiator hi) {
super.setHandlerInstantiator(hi);
}
}
这是我的 SpringBeanHandlerInstantiator 类:
@Component
public class SpringBeanHandlerInstantiator extends HandlerInstantiator {
private ApplicationContext applicationContext;
@Autowired
public SpringBeanHandlerInstantiator(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public JsonDeserializer<?> deserializerInstance(DeserializationConfig dc, Annotated antd, Class<? extends JsonDeserializer<?>> type) {
try {
return (JsonDeserializer<?>) applicationContext.getBean(type);
} catch (Exception e) {
}
return null;
}
@Override
public KeyDeserializer keyDeserializerInstance(DeserializationConfig dc, Annotated antd, Class<? extends KeyDeserializer> type) {
try {
return (KeyDeserializer) applicationContext.getBean(type);
} catch (Exception e) {
}
return null;
}
@Override
public JsonSerializer<?> serializerInstance(SerializationConfig sc, Annotated antd, Class<? extends JsonSerializer<?>> type) {
try {
return (JsonSerializer<?>) applicationContext.getBean(type);
} catch (Exception e) {
}
return null;
}
@Override
public TypeResolverBuilder<?> typeResolverBuilderInstance(MapperConfig<?> mc, Annotated antd, Class<? extends TypeResolverBuilder<?>> type) {
try {
return (TypeResolverBuilder<?>) applicationContext.getBean(type);
} catch (Exception e) {
}
return null;
}
@Override
public TypeIdResolver typeIdResolverInstance(MapperConfig<?> mc, Annotated antd, Class<? extends TypeIdResolver> type) {
try {
return (TypeIdResolver) applicationContext.getBean(type);
} catch (Exception e) {
}
return null;
}
}
这是我的域实体类,序列化器和反序列化器是静态内部类:
@JsonSerialize(using = User.Serializer.class)
@JsonDeserialize(using = User.Deserializer.class)
public class User {
@Component
public static class Serializer extends JsonSerializer<User> {
@Override
public void serialize(User obj, JsonGenerator jg, SerializerProvider sp) throws IOException, JsonProcessingException {
// Cut
}
}
@Component
public static class Deserializer extends JsonDeserializer<User> {
@Autowired
SomeService someService;
@Override
public User deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
User user = new User();
// Cut
// Use someService here
}
}
// Cut
}
我试图在ObjectMapperContextResolver.getContext(Class类型)中放置一个brakpoint,但它永远不会被击中,我怀疑这是问题的根源,但经过两天的尝试和研究球衣文档后,我的想法已经用完了。
任何人都可以指出我如何正确地解决这个问题?
答案 0 :(得分:5)
经过进一步尝试后,发现ObjectMapperContextResolver上的@Component导致Jersey 2.x不使用提供程序,即使它在Jersey配置类中显式注册。这与Jersey 1.x行为相反,需要@Component。
删除它就行了,但看起来很奇怪。 ObjectMapperContextResolver中的@Autowired SpringObjectMapper仍由Jersey注入。
从球衣文件中我无法判断这是设计还是错误。