6

I have a solution using Spring Data JPA and a REST Controller in Spring Web MVC. The persistence provider is Hibernate.

The persistence layer is built using Spring Repositories and between de REST Controller and the repository exists a Service Layer:

Entity <--> Repository <--> Service <--> Controller

At entity level, I have @OneToMany fields with FetchType = LAZY.

When the REST Controller make the serialization, the fetching is made, but this is undesirable in some cases.

I already tried with @JSONInclude Jackson annotation and the serialization still occurs.

Can somebody help me with a proved solution?

1

5 Answers 5

7

If I understood you properly, you want to serialize only when the lazy loaded collection is fetched, but you don't want the serialization to trigger the fetching.

If that is the case you should use the jackson-datatype-hibernate, and added as their docs already explains

public class HibernateAwareObjectMapper extends ObjectMapper {

    public HibernateAwareObjectMapper() {
        registerModule(new Hibernate4Module());
    }
}

than register

 <mvc:annotation-driven>
        <mvc:message-converters>
            <!-- Use the HibernateAware mapper instead of the default -->
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper">
                    <bean class="path.to.your.HibernateAwareObjectMapper" />
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

The module has a Feature.FORCE_LAZY_LOADING settings, that tells whether the object should be forced to be loaded and then serialized, which is by default set to false which I believe is the behaviour you need

Sign up to request clarification or add additional context in comments.

1 Comment

This resolve the problem exactly how I need. Thank you very much!
1

Simple architectural solution is not to use model Entity as Data Transfer Object. Make Simple POJO as Data transfer Object. In the conversion logic you could easily put try and catch block for LazyInitializationException. And thus your POJO is always serializable and You can use it on your controller.

Comments

1

Use the @JsonIgnore annotation if you ALWAYS want to skip this particular field. use @JsonView if you want to dynamically determine which field(s) to skip. Note that @JsonView is a Jackson specific annotation, but since you're already using Jackson, things should be fine.

2 Comments

@JsonView looks very nice. I'm going to test it to see if this avoid the lazy fetching... I will let you know how this is going...
I try with JsonView unsuccessfully. Thinking about my issue, using JsonView will not fit in large and complex model scenarios. Anyway, thank you for your solution.
1

You can solve this problem with wit 2 steps with jackson-datatype-hibernate:

kotlin example

  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.

Comments

0

We can do this by adding Hibernate4Module (which support Lazy objects) to the default MappingJackson2HttpMessageConverter that Spring already provide and by adding it to HttpMessageConverters.

So we need to extend our spring config class from WebMvcConfigurerAdapter and override the method configureMessageConverters and add MappingJackson2HttpMessageConverter with the Hibernate4Module registered in it.

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    //Here we add our custom-configured HttpMessageConverter
    converters.add(jacksonMessageConverter());
    super.configureMessageConverters(converters);
}

// Here we register the Hibernate4Module into an ObjectMapper, 
// then use this custom ObjectMapper
// to the MessageConverter
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;

}

1 Comment

This disable the fetching and the serialization of the field permanently. What I want is to avoid the fetching at the serialization. If the fetch is done with JPQL, the serialization must be done.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.