Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I implement toString() in a class that is mapped with Hibernate?

I have an instance of a class that I got from a Hibernate session. That session is long gone. Now, I'm calling toString() and I'm getting the expected LazyInitializationException: could not initialize proxy - no Session since I'm trying to access a reference which Hibernate didn't resolve during loading of the instance (lazy loading).

I don't really want to make the loading eager since it would change the query from about 120 characters to over 4KB (with eight joins). And I don't have to: All I want to display in toString() is the ID of the referenced object; i.e. something that Hibernate needs to know at this point in time (or it couldn't do the lazy loading).

So my question: How do you handle this case? Never try to use references in toString()? Or do you call toString() in the loading code just in case? Or is there some utility function in Hibernate which will return something useful when I pass it a reference which might be lazy? Or do you avoid references in toString() altogether?

like image 746
Aaron Digulla Avatar asked Nov 12 '09 13:11

Aaron Digulla


People also ask

In which class toString () method is defined?

Object class is the parent class in Java. It contains the toString method. The toString method is used to return a string representation of an object.

What is the default implementation of the toString method in the object class?

By default the toString() method will return a string that lists the name of the class followed by an @ sign and then a hexadecimal representation of the memory location the instantiated object has been assigned to.

How do you toString method is invoked?

The toString() method returns the String representation of the object. If you print any object, Java compiler internally invokes the toString() method on the object. So overriding the toString() method, returns the desired output, it can be the state of an object etc. depending on your implementation.

Is toString required for all classes?

Not unless you want the child classes to provide a more detailed description.


2 Answers

It's possible to do this by setting the accesstype of the ID field to "property". like:

@Entity
public class Foo {
    // the id field is set to be property accessed
    @Id @GeneratedValue @AccessType("property")
    private long id;
    // other fields can use the field access type
    @Column private String stuff;
    public long getId() { return id; }
    public void setId(long id) { this.id = id; }
    String getStuff() { return stuff; }
    // NOTE: we don't need a setStuff method
}

It's explained here. This way the id field is allways populated when a proxy is created.

like image 158
EJB Avatar answered Sep 28 '22 04:09

EJB


I've found a workaround:

public static String getId (DBObject dbo)
{
    if (dbo == null)
        return "null";

    if (dbo instanceof HibernateProxy)
    {
        HibernateProxy proxy = (HibernateProxy)dbo;
        LazyInitializer li = proxy.getHibernateLazyInitializer();
        return li.getIdentifier ().toString ();
    }

    try
    {
        return Long.toString (dbo.id ());
    }
    catch (RuntimeException e)
    {
        return "???";
    }
}

So what this code does is it fetches the ID (a 64bit number) from the object. DBObject is an interface which defines long id(). If the object is a Hibernate proxy, then I talk to its LazyInitializer to get the ID. Otherwise, I call id(). Usage:

class Parent {
    DBObject child;
    public String toString () {
        return "Parent (id=..., child=" + getId(child)+")");
    }
}
like image 33
Aaron Digulla Avatar answered Sep 28 '22 04:09

Aaron Digulla