Search code examples
javaspringjacksonlazy-loadinghibernate-4.x

How to use Hibernate4Module


In an effort to avoid using .size to manually load fields, I would like to implement Hibernate4Module. unfortunately, being new at all things configurations, I can't seem to make it work. All I keep getting from java is: Could not write content: could not initialize proxy - no Session.

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"servlet.controller"})
public class ServletConfig extends WebMvcConfigurerAdapter {
    ...
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        ObjectMapper mapper = null;
        for (HttpMessageConverter<?> converter : converters) {
            if (converter instanceof MappingJackson2HttpMessageConverter) {
                mapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper();

            }
        }
        if (mapper == null) {
            MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
            converter.setObjectMapper(mapper = new ObjectMapper());
            converters.add(converter);
        }
        Hibernate4Module hbm = new Hibernate4Module();
        hbm.enable(Feature.FORCE_LAZY_LOADING);
        mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true)
               .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.registerModule(hbm);
    }
    ...
}

can anybody see what I'm doing wrong here?

NOTE

I have been running into some of the efficiency drawbacks, and I am looking into the fesablity of mitigating them outside of DTO's. I am very familiar with the DTO method, the software I am currently working on contains 60 files named "Ext*.java" (containing DTOs using Gson). Each of these is between 100 and 1000 lines long and increases the length of controller methods substantially. Additionally we are going to be trying to add more unit tests. Consequently I am desperate to find a way of eliminating as much DTO code as possible. That said, I am not at all opposed to using DTO's when they are needed, in fact I just finished my first StdSerializer.

With a project being worked on by about 20 people across the continental united states, I am just hoping to be able to impose some order on the chaos.


Solution

  • It's normal that you got yhis exception Hibernate4Module won't keep the Session open, it's not there for that. If you want to keep the EntityManager/Session open as request scoped you can use a OpenEntityManagerInViewInterceptor.

    To register in Java configuration you have to add in the WebMvcConfigurerAdapter class:

        @Autowired
        private EntityManagerFactory emf;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
    
            OpenEntityManagerInViewInterceptor interceptor = new OpenEntityManagerInViewInterceptor();
            interceptor.setEntityManagerFactory(emf);
            registry.addWebRequestInterceptor(interceptor);
        }
    

    But i wouldn't recommend using it with Jackson for multiple reasons.

    First it's known as an Anti-pattern, you should really think about all the implications before implementing it (Connection behind held longer, break of the Separation of concern...). Plus you take the risk to load all the database depending on your JPA Models and you'll have to deal with infinite recursive with Jackson.

    Manually triggering Lazy-loading may looks painfull at first glance but this plus the use DTO (Data transfer object) is for me the most durable solution.