-2

i have no deep knowledge of Gson/Jackson till now. Please bear with me. I have to convert my object into json string. i have tried both Gson and Jackson. My object has a collection which has Fetch by default which is Lazy load. When i get the object with session.get and convert using Gson's gson.toJson(object); it fails to initialize that lazy collection.

1. I don't want to fetch eager.

2. i don't want to ignore it either.

I just want any way that it should return null or empty whatever instead of messing with lazy load collection. Because as far as i know, if its hibernate dependent then it is impossible fetching it out of session. Is there any work around (in both Gson or Jackson) with this issue cox i don't want to always initialize collection(but sometimes for sure)

@Entity
@JsonInclude(Include.NON_NULL)
public class Category {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    private String name;
    @ManyToMany
    private List<Item> itemList;
    //getter setter
}

And in main method

Session s = sessionFactory.openSession();
Transaction t = s.getTransaction();
t.begin();
Category category = null;
try{
    category = s.get(Category.class, 1);
    t.commit();
}catch(Exception e){
    e.printStackTrace();
}finally{
    s.close();
}

try {
    Gson json = new Gson();
    String categoryString = json.toJson(category);
    System.out.println(categoryString);
} catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

it throws

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.company.entity.Category.itemList, could not initialize proxy - no Session

thst
  • 4,235
  • 1
  • 21
  • 38
vicky
  • 439
  • 1
  • 6
  • 16
  • Can you please debug your code and check, if the object you are about to serialize is really transient and is no longer a proxy? GSON is implemented to ignore null values, so it should ignore a collection that is null. Yet, if you are having a proxy object, the collection is there, but it will fail with an exception, when you try to use it outside a session. – thst Aug 13 '17 at 09:46
  • @thst how can i explicitly make an object transient or proxy after getting from hibernate session? can you please explain this? cox i am using @JsonInclude(Include.NON_NULL) but error still persist. – vicky Aug 13 '17 at 11:17
  • https://stackoverflow.com/questions/2216547/converting-hibernate-proxy-to-real-object – thst Aug 13 '17 at 13:33

1 Answers1

1

I will post an answer to this, because it is not a dupe of the questions cited here. There is another question targeting Jackson, but that answer covers only Jackson. Hibernate and Jackson lazy serialization

Before you persist your object with Gson, you need to make sure, that your collections are no more filled with proxies and that the lazy collections are really null and not a proxy that will fail if not in a session (this is the LazyInitializationException you are receiving.

As presented in this question, you can ask hibernate to give you the implementation object instead of the proxy with this code (quoting from Converting Hibernate proxy to real object):

public static <T> T initializeAndUnproxy(T entity) {
    if (entity == null) {
        throw new 
           NullPointerException("Entity passed for initialization is null");
    }

//    Hibernate.initialize(entity);
    if (entity instanceof HibernateProxy) {
        entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer()
                .getImplementation();
    }
    return entity;
}

In your case, I suppose you do not want the initialize() call to happen, so I commented that line out.

Your code should now read:

   Session s = sessionFactory.openSession();
    Transaction t = s.getTransaction();
    t.begin();
    Category category = null;
    try {
        category = s.get(Category.class, 1);
        t.commit();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        s.close();
    }

    try {
        // No more hibernate messing with my object...
        Category theRealThing = initializeAndUnproxy(category);

        Gson json = new Gson();
        String categoryString = json.toJson(theRealThing);
        System.out.println(categoryString);
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

Update: As for the comment, your class is not a proxy anymore. Another suggestion is to use a custom Gson serializer.

I won't give a full example, but you can find a discussion here: https://groups.google.com/forum/?nomobile=true#!topic/google-gson/kDZjEXap_PE

Basically, you rgister a Gson type adapter for collection or list types. Then you use Hibernate.isInitialized() on the collection object. If it is, you will serialize it, if it isn't, you return null.

thst
  • 4,235
  • 1
  • 21
  • 38
  • thanks for your reply. Actually Category itself is not proxy, it just contains itemList which is PersistentBag and i don't want to load it which means i dnt want hibernate to query database for its entry. It should just return null or empty. In your code above, when i pass Category object to this function condition **entity instanceof HibernateProxy** fails. – vicky Aug 14 '17 at 14:03