[java] 가져 오지 않은 지연 개체에 대한 Jackson 직렬화 방지
User 개체를 반환하는 간단한 컨트롤러가 있으며이 사용자는 최대 절전 속성 FetchType.LAZY가있는 특성 좌표를 가지고 있습니다.
이 사용자를 얻으려고 할 때 항상 사용자 개체를 가져 오기 위해 모든 좌표를로드해야합니다. 그렇지 않으면 Jackson이 User를 직렬화하려고 할 때 예외가 발생합니다.
com.fasterxml.jackson.databind.JsonMappingException : 프록시를 초기화 할 수 없음-세션 없음
이는 Jackson이 가져 오지 않은이 객체를 가져 오려고하기 때문입니다. 개체는 다음과 같습니다.
public class User{
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
@JsonManagedReference("user-coordinate")
private List<Coordinate> coordinates;
}
public class Coordinate {
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
@JsonBackReference("user-coordinate")
private User user;
}
그리고 컨트롤러 :
@RequestMapping(value = "/user/{username}", method=RequestMethod.GET)
public @ResponseBody User getUser(@PathVariable String username) {
User user = userService.getUser(username);
return user;
}
Jackson에게 가져 오지 않은 객체를 직렬화하지 않도록 지시하는 방법이 있습니까? jackson-hibernate-module을 구현하기 전에 3 년 전에 게시 된 다른 답변을 찾고 있습니다. 그러나 아마도 새로운 jackson 기능으로 달성 할 수 있습니다.
내 버전은 다음과 같습니다.
- 봄 3.2.5
- 최대 절전 모드 4.1.7
- 잭슨 2.2
미리 감사드립니다.
답변
마침내 해결책을 찾았습니다! 나에게 단서를 준 indybee에게 감사합니다.
튜토리얼 Spring 3.1, Hibernate 4 및 Jackson-Module-Hibernate 에는 Spring 3.1 및 이전 버전에 대한 좋은 솔루션이 있습니다. 그러나 버전 3.1.2부터 Spring에는 튜토리얼에있는 것과 거의 동일한 기능을 가진 자체 MappingJackson2HttpMessageConverter 가 있으므로이 사용자 지정 HTTPMessageConverter를 만들 필요가 없습니다.
javaconfig를 사용하면 HibernateAwareObjectMapper 도 생성 할 필요가 없습니다. Spring이 이미 가지고 있는 기본 MappingJackson2HttpMessageConverter에 Hibernate4Module 을 추가하고이를 애플리케이션의 HttpMessageConverters에 추가하기 만하면 됩니다.
-
WebMvcConfigurerAdapter 에서 스프링 구성 클래스를 확장하고 configureMessageConverters 메서드를 재정의합니다 .
-
그 방법에 추가 에서 이전 메서드에 등록 된 Hibernate4Module 과 함께 MappingJackson2HttpMessageConverter 를 .
구성 클래스는 다음과 같아야합니다.
@Configuration
@EnableWebMvc
public class MyConfigClass extends WebMvcConfigurerAdapter{
//More configuration....
/* Here we register the Hibernate4Module into an ObjectMapper, then set this custom-configured ObjectMapper
* to the MessageConverter and return it to be added to the HttpMessageConverters of our application*/
public MappingJackson2HttpMessageConverter jacksonMessageConverter(){
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper mapper = new ObjectMapper();
//Registering Hibernate4Module to support lazy objects
mapper.registerModule(new Hibernate4Module());
messageConverter.setObjectMapper(mapper);
return messageConverter;
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
//Here we add our custom-configured HttpMessageConverter
converters.add(jacksonMessageConverter());
super.configureMessageConverters(converters);
}
//More configuration....
}
xml 구성이있는 경우 자체 MappingJackson2HttpMessageConverter를 만들 필요가 없지만 자습서 (HibernateAwareObjectMapper)에 나타나는 개인화 된 매퍼를 만들어야하므로 xml 구성은 다음과 같아야합니다.
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.pastelstudios.json.HibernateAwareObjectMapper" />
</property>
</bean>
</mvc:message-converters>
이 답변이 이해하기 쉽고 누군가가이 문제에 대한 해결책을 찾는 데 도움이되기를 바랍니다. 질문이 있으면 언제든지 물어보십시오!
답변
Spring 4.2부터 Spring Boot 및 javaconfig를 사용하여 Hibernate4Module을 등록하는 것은 이제 다음을 구성에 추가하는 것만 큼 간단합니다.
@Bean
public Module datatypeHibernateModule() {
return new Hibernate4Module();
}
심판 : https://spring.io/blog/2014/12/02/latest-jackson-integration-improvements-in-spring
답변
이것은 @rick이 허용하는 솔루션과 유사합니다.
기존 메시지 변환기 구성을 건드리지 않으려면 Jackson2ObjectMapperBuilder
다음과 같이 빈을 선언하면됩니다 .
@Bean
public Jackson2ObjectMapperBuilder configureObjectMapper() {
return new Jackson2ObjectMapperBuilder()
.modulesToInstall(Hibernate4Module.class);
}
Gradle 파일 (또는 Maven)에 다음 종속성을 추가하는 것을 잊지 마십시오.
compile 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate4:2.4.4'
다음이있는 경우 유용합니다. 봄 부츠응용 프로그램과 application.properties
파일 에서 Jackson 기능을 수정하는 기능을 유지하려고 합니다.
답변
Spring Data Rest의 경우 @ r1ckr가 게시 한 솔루션이 작동하는 동안 필요한 것은 Hibernate 버전에 따라 다음 종속성 중 하나를 추가하는 것입니다.
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate4</artifactId>
<version>${jackson.version}</version>
</dependency>
또는
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId>
<version>${jackson.version}</version>
</dependency>
SpringData Rest에는 클래스가 있습니다.
org.springframework.data.rest.webmvc.json.Jackson2DatatypeHelper
애플리케이션 시작시 모듈을 자동 감지하고 등록합니다.
그러나 문제가 있습니다.
답변
XML 구성을 사용 하고을 사용 하는 경우 Jackson Github 계정 에서 권장하는대로 내부 <annotation-driven />
에 중첩해야한다는 것을 알았습니다.<message-converters>
<annotation-driven>
.
이렇게 :
<annotation-driven>
<message-converters>
<beans:bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<beans:property name="objectMapper">
<beans:bean class="com.pastelstudios.json.HibernateAwareObjectMapper" />
</beans:property>
</beans:bean>
</message-converters>
</annotation-driven>
`
답변
Apache CXF 기반 RESTful 서비스에 대한 솔루션을 찾기 위해 여기에 온 사람들을 위해이를 수정하는 구성은 다음과 같습니다.
<jaxrs:providers>
<bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider">
<property name="mapper" ref="objectMapper"/>
</bean>
</jaxrs:providers>
<bean id="objectMapper" class="path.to.your.HibernateAwareObjectMapper"/>
HibernateAwareObjectMapper는 다음과 같이 정의됩니다.
public class HibernateAwareObjectMapper extends ObjectMapper {
public HibernateAwareObjectMapper() {
registerModule(new Hibernate5Module());
}
}
다음 종속성은 2016 년 6 월부터 필요합니다 (Hibernate5를 사용하는 경우).
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId>
<version>2.7.4</version>
</dependency>
답변
다음 솔루션은 Spring 4.3, (non-boot) & Hibernate 5.1에 대한 것입니다. 여기서 우리 는 성능상의 이유로 모든 fetchtype을 fetch=FetchType.LAZY
케이스에서 전환했습니다 fetch=FetchType.EAGER
. 즉시 우리는com.fasterxml.jackson.databind.JsonMappingException: could not initialize proxy
지연로드 문제로 인한 예외를 했습니다.
먼저 다음 Maven 종속성을 추가합니다.
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId>
</dependency>
그런 다음 Java MVC 구성 파일에 다음이 추가됩니다.
@Configuration
@EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
Hibernate5Module h5module = new Hibernate5Module();
h5module.disable(Hibernate5Module.Feature.USE_TRANSIENT_ANNOTATION);
h5module.enable(Hibernate5Module.Feature.FORCE_LAZY_LOADING);
for (HttpMessageConverter<?> mc : converters){
if (mc instanceof MappingJackson2HttpMessageConverter || mc instanceof MappingJackson2XmlHttpMessageConverter) {
((AbstractJackson2HttpMessageConverter) mc).getObjectMapper().registerModule(h5module);
}
}
return;
}
메모:
-
이 모듈없이 Jackson과 유사한 동작을 얻으려면 Hibernate5Module을 만들고 구성해야합니다. 기본값은 호환되지 않는 가정을합니다.
-
우리
WebMvcConfigurerAdapter
는 다른 많은 구성을 가지고 있고 다른 구성 클래스를 피하고 싶었습니다. 이것이WebMvcConfigurationSupport#addDefaultHttpMessageConverters
다른 포스트에서 언급 된 함수를 사용하지 않은 이유 입니다. -
WebMvcConfigurerAdapter#configureMessageConverters
메시지 변환기의 모든 Spring 내부 구성을 비활성화합니다. 우리는 이와 관련된 잠재적 인 문제를 피하는 것을 선호했습니다. -
사용하여
extendMessageConverters
다른 모든 메시지 컨버터의 구성을 잃지 않고 모든 자동 구성 잭슨 클래스에 지원 액세스를. -
사용 하여 기존 변환기에
getObjectMapper#registerModule
를 추가 할 수있었습니다Hibernate5Module
. - 모듈이 JSON 및 XML 프로세서 모두에 추가되었습니다.
이 추가로 Hibernate 및 지연 로딩 문제가 해결되었지만 생성 된 JSON 형식에 잔여 문제가 발생했습니다 . 이 github 문제 에서보고 된 것처럼 hibernate-jackson 지연로드 모듈은 현재 @JsonUnwrapped 주석을 무시하여 잠재적 인 데이터 오류를 유발합니다. 이것은 강제 로딩 기능 설정에 관계없이 발생합니다. 문제는 2016 년부터있었습니다.
노트
지연로드 된 클래스에 다음을 추가하면 내장 ObjectMapper가 hibernate5 모듈을 추가하지 않고도 작동하는 것으로 보입니다.
@JsonIgnoreProperties( {"handler","hibernateLazyInitializer"} )
public class Anyclass {