4

I'm currently running a spring-boot application where an endpoint returns a Page of a particular object stored in the database. For our purpose lets call that object "x". Within "x" there is a list of objects that are set to be lazily fetched.

@Entity
@DynamicUpdate
class x {

      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private Integer id;

      @JsonIgnore
      @OneToMany(mappedBy = "x", cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
      private List<y> lazilyFetchedList;

      @Override
      public Integer getId() {
           return id;
      }

      public void setId(Integer id) {
           this.id = id;
      }

      @JsonIgnore
      public List<y> getLazilyFetchedList() {
           return lazilyFetchedList;
      }

      public void setLazilyFetchedList(List<y> lazilyFetchedList) {
           this.lazilyFetchedList = lazilyFetchedList;
      }
}

I set @JsonIgnore above because I don't want lazilyFetchedList to be sent to the client upon a GET call.

My problem is, even though that field is successfully ignored by jackson as a client viewing the JSON response. But additional querys are still made by hibernate to fetch the lazilyFetchedList when serializing the Java object "x" (even though jackson is not using the result).

I have already tried answers from Avoid Jackson serialization on non fetched lazy objects but none of the answers seem to work.

Here is what my controller looks like:

    @RequestMapping(value = "/{id}/x", method = RequestMethod.GET)
    public ApiResponse<?> findX(@PathVariable Integer id, PagingInfo info) {
        Page<x> page = repo.findX(id, toPageable(info));
        return toResponse(page, FIND_LIST_STATUS);
    } 

Here's what my configuration of the object mapper looks like:

@Configuration
@EnableWebMvc
public class ApiWebConfig extends WebMvcConfigurerAdapter {

@Bean
public ObjectMapper objectMapper() {
    ObjectMapper objectMapper = new ObjectMapper();
    configureDefaultObjectMapper(objectMapper);
    customizeObjectMapper(objectMapper);
    return objectMapper;
}

public static void configureDefaultObjectMapper(ObjectMapper objectMapper) {
    objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);

    objectMapper.registerModule(new Hibernate5Module());

    JavaTimeModule javaTimeModule = new JavaTimeModule();
    javaTimeModule.addSerializer(ZonedDateTime.class, ZonedDateTimeSerializer.INSTANCE);
    javaTimeModule.addSerializer(OffsetDateTime.class, OffsetDateTimeSerializer.INSTANCE);
    objectMapper.registerModule(javaTimeModule);
}

/**
 * Only register a json message converter
 */
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.clear();

    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
    converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON, ActuatorMediaTypes.APPLICATION_ACTUATOR_V1_JSON));
    converter.setObjectMapper(objectMapper());

    converters.add(converter);
}
}

Versions:

  • Spring-Boot 1.5.3
  • Jackson 2.8.6
  • Hibernate 5.0.11.Final
  • jackson-datatype-hibernate5 2.9.0
Zain Khan
  • 71
  • 1
  • 5
  • What happens if you remove the getter/setter? – Ludovic Guillaume Aug 17 '17 at 23:47
  • 2
    Don't use entity class rather create pojo for json.. – surya Aug 18 '17 at 01:30
  • The thing is, I have alot of entities within my project. So creating a pojo for each one would not be a feasible solution, plus I wouldn't want to implement a solution which requires field changes in two different locations since there is a high chance the code would break if anyone were to update that entity. I would like a more general solution that's handled by the libraries themselves. – Zain Khan Aug 18 '17 at 14:25

1 Answers1

11

Add the following dependency to your pom.xml:

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

(add the version if it is not managed by spring-boot-dependencies or spring-boot-starter-parent) Add the following code to your spring configuration class:

@Bean
protected Module module() {
    return new Hibernate5Module();
}

With the following imports:

import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
Kamikazzze
  • 137
  • 2
  • 11