4

My environment

  • jackson-datatype-hibernate 2.3.2
  • Spring-webmvc 3.2.6
  • Hibernate 4.3.4

So basically my application is supposed to return a list of serialized corporations. The corporation class has a set of traveller objects which are lazy loaded(lazy='true' defined in mapping). Consequently they shouldn't be serialized. However, when jackson is serializing the corporations from the controller, for some reason, it also tries to serialize travellers, but it crashes and throws an error: org.hibernate.LazyInitializationException - failed to lazily initialize a collection of role: com.model.core.Corporation.employees

I have googled this issue and I've seen it in a couple of posts but I haven't been able to fix it so far. https://github.com/FasterXML/jackson-datatype-hibernate/issues/25

My code is basically composed of a java "Corporation" class with its hbm.xml mapping. I've also extended the ObjectMapper and set it to the Spring message converter as told in that post (Avoid Jackson serialization on non fetched lazy objects) Then I created a "CorporationMixin" class and annotated it with @JsonIdentityInfo. To finish, I just return the list of corporations from the controller.

Please have a look at my code and give me a hint. I don't know whether the problem is my implementation or a bug in the jackson-datatype-hibernate library.

Mapping hbm :

<class name="com.model.core.Corporation" table="corporation" lazy="false">
 <id name="id" column="corporation_id" type="java.lang.String" unsaved-value="0">
    <generator class="guid"/>
  </id>
 <set lazy="true" name="employees" inverse="false" cascade="delete">
   <key column="corporation_id"/>
   <one-to-many class="com.model.core.Employee"/>
 </set>
...
</class>

"Corporation" entity:

public class Corporation implements Serializable
{
 private String id;
 private Set<Employee> employees;
...(get/set)
}

Mapper added to servlet-context.xml:

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

HibernateAwareObjectMapper class:

public class HibernateAwareObjectMapper extends ObjectMapper {

    public HibernateAwareObjectMapper() {
        registerModule(new Hibernate4Module());
        this.addMixInAnnotations(Corporation.class, CorporationMixin.class);
    }
}

CorporationMixin class:

@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
public abstract class CorporationMixin {
}

Controller class which returns the serialized corporations:

@RequestMapping(value="/secured/corporations/init",method = RequestMethod.GET,produces = "application/json") 
    @ResponseBody 
    public ResponseEntity<List<Corporation>> getUsersList()
    {
        List<Corporation> corps = corporationDao.getTopCorporations();
        return new ResponseEntity<List<Corporation>>(corps, HttpStatus.OK);
    }

There's a workaround to avoid the crash of hibernate which is basically adding this in web.xml

<filter>
    <filter-name>hibernateFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    <init-param>
      <param-name>singleSession</param-name>
      <param-value>false</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>hibernateFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

But that doesn't really fix the initial issue which is why jackson tries to serialize collections whose lazy=true??

Thanks for your help!

Community
  • 1
  • 1
jaybe78
  • 363
  • 4
  • 18
  • Have you checked out this http://stackoverflow.com/questions/21708339/avoid-jackson-serialization-on-non-fetched-lazy-objects? – geoand May 02 '14 at 12:27
  • Yes I checked it. It's an old post and that person wasn't using the jackson-datatype-hibernate library that was specifically created to deal with Hibernate specific datatypes and properties; especially lazy-loading aspects. Also that was an old version of Jackson since, in the last version, annotations like "JsonManagedReference" and "JsonBackReference" are not used anymore. They have been replaced by @JsonIdentityInfo – jaybe78 May 02 '14 at 12:43
  • Have you seen this https://github.com/FasterXML/jackson-datatype-hibernate/issues/25? It uses Spring Boot with jackson-datatype-hibernate4 and seems to be working well – geoand May 02 '14 at 13:01
  • Yes I've posted on it. the issue hasn't been resolved. what do you mean "Spring Boot" ? what is it? – jaybe78 May 02 '14 at 13:11
  • http://projects.spring.io/spring-boot/ It's a new Spring project that vastly simplifies configuration. That project that is mentioned in the issue and can be found at https://github.com/ralscha/jacksonhibernate, uses it, and works perfectly (I tried it) – geoand May 02 '14 at 13:13
  • AS you've seen The exception occurs when you enable FORCE_LAZY_LOADING in the class ch.rasc.jacksonhibernate.Start. At this point I don't know what to do!? :( – jaybe78 May 02 '14 at 13:57
  • I would suggest that you force Hibernate to load `Set` before handing off the request to Jackson. If you need help on how to do that, you should post the code that you are using for `corporationDao.getTopCorporations()` – geoand May 02 '14 at 14:00
  • Well to force hibernate to load the employees I just need to add the OpenSessionInViewFilter in the web.xml and it will load all sub lists. But that's not gonna help me since I really need to find a way to not load the sub lists because it really slows the performance of my web app down. – jaybe78 May 02 '14 at 14:07
  • Not necessarily. You can alter the query you are using in `corporationDao.getTopCorporations()` to make Hibernate fetch the data you want – geoand May 02 '14 at 14:10
  • It's a basic HQL query from com.model.core.Corporation corp where corp.id=corp.parent.id I don't think the query would change anything, it's in the mapping xml that the lazy attribute is configured and indicates whether the object should be fetched or not – jaybe78 May 02 '14 at 14:16
  • Your query would be `select distinct corp from com.model.core.Corporation corp left join fetch corp.employees where corp.id=corp.parent.id`. By specifying `left join fetch` you force Hibernate to perform an SQL left join on the Employees table. Try it out and let me know – geoand May 02 '14 at 14:20
  • I'll give it a try, that could work. But that means I would have to rewrite all my queries lol Well at least there's a solution! Cheers – jaybe78 May 02 '14 at 14:28
  • If it works, let me know so I can post it as an answer for future viewers to see without needing to weed through the comments :) – geoand May 02 '14 at 14:31
  • I don't think that is the right answer to the problem, it is more of like a workaround. Using left join is the same as eager fetch, which causes overhead on performance when the data is not necessarily needed. – lorraine batol Aug 24 '14 at 03:41
  • that issue was basically a bug from the library itself. There's been some upgrade of jackson library and it looks like the bug has been closed there so I guess it's been fixed.Cheers – jaybe78 Apr 25 '16 at 22:31

0 Answers0