0

I am learning Spring Boot and actually I am trying to fetch lazy loaded associations just when it is needed and it does not include the Json generated during the page rendering.

I have a class Person which have an auto-association "father":

@Entity(name = "Person")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long idPerson;

    private String Name;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "idFather")
    private Person father;

    /*Getters and setters ommited*/
}

I have configured an object mapper with jackson as suggested by this site:

@Bean
public Jackson2ObjectMapperBuilder configureObjectMapper() {
    return new Jackson2ObjectMapperBuilder()
            .modulesToInstall(Hibernate5Module.class);
}

Finally I have a GET endpoint that will return a single Person if the id is informed or list everyone otherwise. My PersonRepository simple extends the CrudRepository interface.

When I try to fetch a single record the father is not loaded as expected:

//localhost:9000/person/2
{"idPerson":2,"name":"Luke Skywalker","father":null}

But if I try to retrieve all People (CrudRepository.listAll) the associations are fetched:

//localhost:9000/person
[  
   {  
      "idPerson":1,
      "name":"Darth Vader",
      "father":null
   },
   {  
      "idPerson":2,
      "name":"Luke Skywalker",
      "father":{  
         "idPerson":1,
         "name":"Darth Vader",
         "father":null
      }
   }
]

I do not desire this behavior and I am probably missing some configuration on the Object Mapper.

Does someone have an idea about what I should do?

Edit:

I dont think this is a duplication to Avoid Jackson serialization on non fetched lazy objects.

First: The answer provided there is old and WebMvcConfigurerAdapter is deprecated on Hibernate 5.

Second: Based on Configure Jackson to omit lazy-loading attributes in Spring Boot. I suspect the solution provided by @r1ckr on the first topic is actually equivalent to what I am using:

@Bean
public Jackson2ObjectMapperBuilder configureObjectMapper() {
    return new Jackson2ObjectMapperBuilder()
            .modulesToInstall(Hibernate5Module.class);
}

Third: Even knowing abot the deprecation I tried the solution proposed with the same behavior which reinforced the second point.

Fourth: I tried the same approach using the actual interface WebMvcConfigurer and again achieved the same behavior.

@Configuration
@EnableWebMvc
public class Configuration implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(jacksonMessageConverter());
        WebMvcConfigurer.super.configureMessageConverters(converters);
    }

    public MappingJackson2HttpMessageConverter jacksonMessageConverter() {
        MappingJackson2HttpMessageConverter messageConverter = 
            new MappingJackson2HttpMessageConverter();

        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new Hibernate5Module());
        messageConverter.setObjectMapper(mapper);
        return messageConverter;
    }
}
marcellorvalle
  • 1,631
  • 3
  • 17
  • 30
  • Possible duplicate of [Avoid Jackson serialization on non fetched lazy objects](https://stackoverflow.com/questions/21708339/avoid-jackson-serialization-on-non-fetched-lazy-objects) – K.Nicholas May 28 '18 at 00:27
  • I don't think the solution there solves my problem. According to https://stackoverflow.com/questions/33727017/configure-jackson-to-omit-lazy-loading-attributes-in-spring-boot what @r1ckr has done is now equivalent to the configuration I used with jackson object mapper. Still the lazy relatioships are fetched when I retrieve an entity collection. – marcellorvalle May 28 '18 at 02:40
  • Are you using Spring Boot 2? If yes IMHO you don't need to configure an object mapper. This should work out of the box – Simon Martinelli May 28 '18 at 06:17
  • I don't think so. If I do not use the Jackson Mapper it will fetch the father as soon as it render the json. Now that I enabled sql logging I can see it clearer. – marcellorvalle May 29 '18 at 01:02

1 Answers1

0

I just figured it out, some concepts about Hibernate was not fully understood by me and I imagined it was unnecessarily fetching the associations when retrieving all entities.

As I enabled the SQL log I could see the framework was issuing a single select statment. It makes sense: if I have all data in-memory, why not populate the associations early and avoid the trouble to fetch the data again on the future? Very clever indeed.

marcellorvalle
  • 1,631
  • 3
  • 17
  • 30