Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent hibernate5 from lazy fetching when jackson serializes json object?

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
like image 335
Zain Khan Avatar asked Dec 24 '22 15:12

Zain Khan


1 Answers

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;
like image 60
Kamikazzze Avatar answered May 14 '23 01:05

Kamikazzze