title: Jackson triggering JPA Lazy Fetching on serialization
body: <p>We have a back-end component that exposes database (PostgreSQL) data via JPA to RESTful API.</p>
  
  <p>The problem is that when sending a JPA entity as a REST response, I can see Jackson triggering all Lazy JPA relationships.</p>
  
  <hr>
  
  <p>Code example (simplified):</p>
  
  <pre class="lang-java prettyprint-override"><code>import org.springframework.hateoas.ResourceSupport;
  import com.fasterxml.jackson.annotation.JsonIdentityInfo;
  import com.fasterxml.jackson.annotation.ObjectIdGenerators;
  import org.springframework.transaction.annotation.Transactional;
  
  import javax.persistence.CascadeType;
  import javax.persistence.Entity;
  import javax.persistence.GeneratedValue;
  import javax.persistence.Id;
  import javax.persistence.OneToMany;
  import java.io.Serializable;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.List;
  
  @Entity
  @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")//for resolving this bidirectional relationship, otherwise StackOverFlow due to infinite recursion
  public class Parent extends ResourceSupport implements Serializable {
  
      private static final long serialVersionUID = 1L;
  
      @Id
      @GeneratedValue
      private Long id;
  
      //we actually use Set and override hashcode&amp;equals
      @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
      private List&lt;Child&gt; children = new ArrayList&lt;&gt;();
  
      @Transactional
      public void addChild(Child child) {
  
          child.setParent(this);
          children.add(child);
      }
  
      @Transactional
      public void removeChild(Child child) {
  
          child.setParent(null);
          children.remove(child);
      }
  
      public Long getId() {
  
          return id;
      }
  
      @Transactional
      public List&lt;Child&gt; getReadOnlyChildren() {
  
          return Collections.unmodifiableList(children);
      }
  }
  </code></pre>
  
  <pre class="lang-java prettyprint-override"><code>import com.fasterxml.jackson.annotation.JsonIdentityInfo;
  import com.fasterxml.jackson.annotation.ObjectIdGenerators;
  
  import javax.persistence.Entity;
  import javax.persistence.GeneratedValue;
  import javax.persistence.Id;
  import javax.persistence.JoinColumn;
  import javax.persistence.ManyToOne;
  import java.io.Serializable;
  
  @Entity
  @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
  public class Child implements Serializable {
  
      private static final long serialVersionUID = 1L;
  
      @Id
      @GeneratedValue
      private Long id;
  
      @ManyToOne
      @JoinColumn(name = "id")
      private Parent parent;
  
      public Long getId() {
  
          return id;
      }
  
      public Parent getParent() {
  
          return parent;
      }
  
      /**
       * Only for usage in {@link Parent}
       */
      void setParent(final Parent parent) {
  
          this.parent = parent;
      }
  }
  </code></pre>
  
  <pre class="lang-java prettyprint-override"><code>import org.springframework.data.repository.CrudRepository;
  
  public interface ParentRepository extends CrudRepository&lt;Parent, Long&gt; {}
  </code></pre>
  
  <pre class="lang-java prettyprint-override"><code>import com.avaya.adw.db.repo.ParentRepository;
  import org.springframework.beans.factory.annotation.Value;
  import org.springframework.hateoas.Link;
  import org.springframework.http.HttpHeaders;
  import org.springframework.http.HttpStatus;
  import org.springframework.http.ResponseEntity;
  import org.springframework.web.bind.annotation.CrossOrigin;
  import org.springframework.web.bind.annotation.GetMapping;
  import org.springframework.web.bind.annotation.PathVariable;
  import org.springframework.web.bind.annotation.RequestMapping;
  import org.springframework.web.bind.annotation.RestController;
  
  import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
  
  @RestController
  @RequestMapping("/api/v1.0/parents")
  public class ParentController {
  
      private final String hostPath;
  
      private final ParentRepository parentRepository;
  
      public ParentController(@Value("${app.hostPath}") final String hostPath,
                            final ParentRepository parentRepository) {
  
          // in application.properties: app.hostPath=/api/v1.0/
          this.hostPath = hostPath; 
          this.parentRepository = parentRepository;
      }
  
      @CrossOrigin(origins = "*")
      @GetMapping("/{id}")
      public ResponseEntity&lt;?&gt; getParent(@PathVariable(value = "id") long id) {
  
          final Parent parent = parentRepository.findOne(id);
          if (parent == null) {
              return new ResponseEntity&lt;&gt;(new HttpHeaders(), HttpStatus.NOT_FOUND);
          }
          Link selfLink = linkTo(Parent.class)
                  .slash(hostPath + "parents")
                  .slash(parent.getId()).withRel("self");
          Link updateLink = linkTo(Parent.class)
                  .slash(hostPath + "parents")
                  .slash(parent.getId()).withRel("update");
          Link deleteLink = linkTo(Parent.class)
                  .slash(hostPath + "parents")
                  .slash(parent.getId()).withRel("delete");
          Link syncLink = linkTo(Parent.class)
                  .slash(hostPath + "parents")
                  .slash(parent.getId())
                  .slash("sync").withRel("sync");
          parent.add(selfLink);
          parent.add(updateLink);
          parent.add(deleteLink);
          parent.add(syncLink);
          return new ResponseEntity&lt;&gt;(adDataSource, new HttpHeaders(), HttpStatus.OK);
      }
  }
  </code></pre>
  
  <hr>
  
  <p>So, if I send GET <code>.../api/v1.0/parents/1</code>, the response is the following:</p>
  
  <pre class="lang-json prettyprint-override"><code>{
      "id": 1,
      "children": [
          {
              "id": 1,
              "parent": 1
          },
          {
              "id": 2,
              "parent": 1
          },
          {
              "id": 3,
              "parent": 1
          }
      ],
      "links": [
          {
              "rel": "self",
              "href": "http://.../api/v1.0/parents/1"
          },
          {
              "rel": "update",
              "href": "http://.../api/v1.0/parents/1"
          },
          {
              "rel": "delete",
              "href": "http://.../api/v1.0/parents/1"
          },
          {
              "rel": "sync",
              "href": "http://.../api/v1.0/parents/1/sync"
          }
      ]
  }
  </code></pre>
  
  <p>But I expect it to not contain <code>children</code> or contain it as an empty array or null -- to not fetch the actual values from the database.</p>
  
  <hr>
  
  <p>The component has the following notable maven dependencies:</p>
  
  <pre>
   - Spring Boot Starter 1.5.7.RELEASE
   - Spring Boot Starter Web 1.5.7.RELEASE (version from parent)
   - Spring HATEOAS 0.23.0.RELEASE
   - Jackson Databind 2.8.8 (it's 2.8.1 in web starter, I don't know why we overrode that)
   - Spring Boot Started Data JPA 1.5.7.RELEASE (version from parent) -- hibernate-core 5.0.12.Final
  </pre>
  
  <hr>
  
  <h1>Tried so far</h1>
  
  <p>Debugging showed that there is one <code>select</code> on <code>Parent</code> at <code>parentRepository.findOne(id)</code> and another one on <code>Parent.children</code> during serialization.</p>
  
  <p>At first, I tried applying <code>@JsonIgnore</code> to lazy collections, but that ignores the collection even if it actually contains something (has already been fetched).</p>
  
  <p>I found out about <a href="https://github.com/FasterXML/jackson-datatype-hibernate" rel="noreferrer">jackson-datatype-hibernate</a> project that claims to </p>
  
  <blockquote>
    <p>build Jackson module (jar) to support JSON serialization and
    deserialization of Hibernate (<a href="http://hibernate.org" rel="noreferrer">http://hibernate.org</a>) specific datatypes
    and properties; <strong>especially lazy-loading aspects</strong>.</p>
  </blockquote>
  
  <p>The idea of this is to register <code>Hibernate5Module</code> (if version 5 of hibernate is used) to the <code>ObjectMapper</code> and that should do it as the module has a setting <code>FORCE_LAZY_LOADING</code> set to <code>false</code> by default.</p>
  
  <p>So, I included this dependency <code>jackson-datatype-hibernate5</code>, version 2.8.10 (from parent). And googled a way to <a href="https://docs.spring.io/spring-boot/docs/1.5.7.RELEASE/reference/htmlsingle/#howto-customize-the-jackson-objectmapper" rel="noreferrer">enable it in Spring Boot</a> (I also found other sources but they mostly refer to this).</p>
  
  <hr>
  
  <p><strong>1. Straightforward add module</strong> (Spring Boot specific):</p>
  
  <pre class="lang-java prettyprint-override"><code>import com.fasterxml.jackson.databind.Module;
  import com.fasterxml.jackson.databind.ObjectMapper;
  import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
  import org.springframework.context.annotation.Bean;
  import org.springframework.context.annotation.Configuration;
  
  @Configuration
  public class HibernateConfiguration {
  
      @Bean
      public Module disableForceLazyFetching() {
  
          return new Hibernate5Module();
      }
  }
  </code></pre>
  
  <p>Debugging showed, that <code>ObjectMapper</code> that is being invoked by Spring when it returnes <code>Parent</code> contains this module and has force lazy setting set to false just as expected. But then it still fetches <code>children</code>.</p>
  
  <p>Further debugging showed: <code>com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields</code> iterates through properties (<code>com.fasterxml.jackson.databind.ser.BeanPropertyWriter</code>) and calls their method <code>serializeAsField</code>, where the first line is: <code>final Object value = (_accessorMethod == null) ? _field.get(bean) : _accessorMethod.invoke(bean);</code> which is triggering lazy loading. I could not spot any place where the code would actualy care about that hibernate module.</p>
  
  <p><strong>upd</strong> Also tried enabling <code>SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS</code> that should include actual id of the lazy property, rather than <code>null</code> (which is the default).</p>
  
  <pre><code>@Bean
  public Module disableForceLazyFetching() {
  
      Hibernate5Module module = new Hibernate5Module();
      module.enable(Hibernate5Module.Feature.SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS);
  
      return module;
  }
  </code></pre>
  
  <p>Debugging showed that the option is enabled but that still had no effect.</p>
  
  <hr>
  
  <p><strong>2. Instruct Spring MVC to add a module</strong>:
  </p>
  
  <pre><code>import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
  import org.springframework.context.annotation.Configuration;
  import org.springframework.http.converter.HttpMessageConverter;
  import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
  import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
  import org.springframework.web.servlet.config.annotation.EnableWebMvc;
  import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
  
  import java.util.List;
  
  @Configuration
  @EnableWebMvc
  public class HibernateConfiguration extends WebMvcConfigurerAdapter {
  
      @Override
      public void configureMessageConverters(List&lt;HttpMessageConverter&lt;?&gt;&gt; converters) {
          Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
                  .modulesToInstall(new Hibernate5Module());
          converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
      }
  }
  </code></pre>
  
  <p>This also successfully adds the module to the <code>ObjectMapper</code> that is being invoked, but it still has no effect in my case.</p>
  
  <hr>
  
  <p><strong>3. Completely replace <code>ObjectMapper</code> with a new one</strong>:
  </p>
  
  <pre><code>import com.fasterxml.jackson.databind.ObjectMapper;
  import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
  import org.springframework.context.annotation.Bean;
  import org.springframework.context.annotation.Configuration;
  import org.springframework.context.annotation.Primary;
  
  @Configuration
  public class HibernateConfiguration {
  
      @Primary
      @Bean(name = "objectMapper")
      public ObjectMapper hibernateAwareObjectMapper(){
  
          ObjectMapper mapper = new ObjectMapper();
          mapper.registerModule(new Hibernate5Module());
  
          return mapper;
      }
  }
  </code></pre>
  
  <p>Again, I can see the module is added but that has no effect for me.</p>
  
  <hr>
  
  <p>There are other ways to add this module, but I am not failing in this, since the module is added.</p>