У меня возникли проблемы с переносом Джерси с 1.x до 2.x. Мое приложение использует Джерси для предоставления веб-сервисов REST с данными, которые обслуживаются в JSON через Jackson и Spring 4 для обработки инъекции зависимостей.
В Джерси 1.xi используется для записи JsonDeserializer в качестве компонентов, управляемых Spring, поэтому я могу получить доступ к моим сервисам для загрузки с уровня уровня защиты моего объекта домена во время десериализации, но в 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 избыточна с регистрацией в классе конфигурации ресурса.
Это мой класс 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
}
Я попытался установить brakpoint в ObjectMapperContextResolver.getContext(тип класса), но он никогда не попадает, я подозреваю, что корень проблемы, но после двух дней попыток и изучения джерси docs у меня заканчиваются идеи.
Кто-нибудь может указать мне, как добиться этого правильно?