Avoid Jackson serialization on non fetched lazy objects

前端 未结 14 1884
终归单人心
终归单人心 2020-11-22 13:02

I have a simple controller that return a User object, this user have a attribute coordinates that have the hibernate property FetchType.LAZY.

When I try to get this

相关标签:
14条回答
  • 2020-11-22 13:30

    For those who came here looking to find the solution for Apache CXF-based RESTful service, the configuration that fixes it is below:

    <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"/>
    

    Where HibernateAwareObjectMapper is defined as:

    public class HibernateAwareObjectMapper extends ObjectMapper {
        public HibernateAwareObjectMapper() {
            registerModule(new Hibernate5Module());
        }
    }
    

    The following dependency is required as of June 2016 (provided you're using Hibernate5):

    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-hibernate5</artifactId>
        <version>2.7.4</version>
    </dependency>  
    
    0 讨论(0)
  • 2020-11-22 13:32

    You can use the following helper from Spring Data Rest project:

    Jackson2DatatypeHelper.configureObjectMapper(objectMapper);
    
    0 讨论(0)
  • 2020-11-22 13:32

    I made a very simple solution to this problem.

    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    public Set<Pendency> getPendencies() {
        return Hibernate.isInitialized(this.pendencies) ? Collections.unmodifiableSet(this.pendencies) : new HashSet<>();
    }
    

    In my case I was giving the error because whenever I was returning a pendencies, as a good practice I converted it to a list that cannot be modified, but how it could or might not be in lazy depending on the method I used to get instance (with or without fetch), I do a test before it was initialized by Hibernate and add the annotation that prevents serializing an empty property and that solved my problem.

    0 讨论(0)
  • 2020-11-22 13:33

    In the case of Spring Data Rest then, while the solution posted by @r1ckr works, all that is required is to add one of the following dependencies depending on your Hibernate version:

    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-hibernate4</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    

    or

    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-hibernate5</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    

    Within Spring Data Rest there is a class:

    org.springframework.data.rest.webmvc.json.Jackson2DatatypeHelper

    which will auto-detect and register the Module on application start-up.

    There is however an issue:

    Issue Serializing Lazy @ManyToOne

    0 讨论(0)
  • 2020-11-22 13:35

    I've spent whole day trying to solve the same problem. You can do it without changing existing message converters configuration.

    In my opinion the easiest way to solve this problem only with 2 steps with help of jackson-datatype-hibernate:

    kotlin example (same as java):

    1. Add In build.gradle.kts:
    implementation("com.fasterxml.jackson.datatype:jackson-datatype-hibernate5:$jacksonHibernate")
    
    1. Create @Bean
       @Bean
       fun hibernate5Module(): Module = Hibernate5Module()
    

    • Notice that Module is com.fasterxml.jackson.databind.Module, not java.util.Module

    • Also good practice is to add @JsonBackReference & @JsonManagedReference to @OneToMany & @ManyToOne relationships. @JsonBackReference could be only 1 in class.

    0 讨论(0)
  • 2020-11-22 13:36

    The following solution is for Spring 4.3, (non-boot) & Hibernate 5.1 where we transitioned all fetchtypes to fetch=FetchType.LAZY from cases of fetch=FetchType.EAGER for performance reasons. Immediately we saw the com.fasterxml.jackson.databind.JsonMappingException: could not initialize proxy exception due to the lazy load issue.

    First, we add the following maven dependency:

    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-hibernate5</artifactId>
    </dependency>  
    

    Then the following is added to our Java MVC configuration file:

    @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;
    }
    

    Notes:

    • You need to create and configure the Hibernate5Module to get behavior similar to Jackson without this module. The default makes incompatible assumptions.

    • Our WebMvcConfigurerAdapter has a lot of other configuration in it and we wanted to avoid another configuration class, which is why we didn't use the WebMvcConfigurationSupport#addDefaultHttpMessageConverters function that has been referred to on other posts.

    • WebMvcConfigurerAdapter#configureMessageConverters disables all of Spring's internal configuration of message converters. We preferred to avoid the potential issues around this.

    • Using extendMessageConverters enabled access to all the automatically-configured Jackson classes without losing the configuration of all other message converters.

    • Using getObjectMapper#registerModule we were able to add the Hibernate5Module to the existing converters.

    • The module was added to both the JSON and XML processors

    This addition solved the issue with Hibernate and lazy loading but caused a residual issue with the generated JSON format. As reported in this github issue, the hibernate-jackson lazy load module currently ignores the @JsonUnwrapped annotation, leading to potential data errors. This happens regardless of the force-loading feature setting. The problem has been there since 2016.


    Note

    It appears that by adding the following to classes that are lazy-loaded, the built-in ObjectMapper works without adding the hibernate5 module:

    @JsonIgnoreProperties(  {"handler","hibernateLazyInitializer"} )
    public class Anyclass {
    
    0 讨论(0)
提交回复
热议问题