tags:

views:

429

answers:

6

The no-argument constructor is a requirement (tools like Hibernate use reflection on this constructor to instantiate objects).

I got this hand-wavy answer but could somebody explain further? Thanks

+21  A: 

Hibernate instantiates your objects. So it needs to be able to instnatiate them. If there isn't a no-arg constructor, Hibernate won't know how to instantiate it - what argument to pass.

Bozho
+2  A: 

Hibernate needs to create instances as result of your queries (via reflection), Hibernate relies on the no-arg constructor of entities for that, so you need to provide a no-arg constructor. What is not clear?

Pascal Thivent
+7  A: 

Hibernate, and code in general that creates objects via reflection use Class<T>.newInstance() to create a new instance of your classes. This method requires a public no-arg constructor to be able to instantiate the object. For most use cases, providing a no-arg constructor is not a problem.

There are hacks based on serialization that can work around not having a no-arg constructor, since serialization uses jvm magic to create objects without invoking the constructor. But this is not available across all VMs. For example, XStream can create instances of objects that don't have a public no-arg constructor, but only by running in a so-called "enhanced" mode which is available only on certain VMs. (See the link for details.) Hibernate's designers surely chose to maintain compatibility with all VMs and so avoids such tricks, and uses the officially supported reflection method Class<T>.newInstance() requiring a no-arg constructor.

mdma
+1  A: 

Actually, you can instantiate classes which have no 0-args constructor; you can get a list of a class' constructors, pick one and invoke it with bogus parameters.

While this is possible, and I guess it would work and wouldn't be problematic, you'll have to agree that is pretty weird.

Constructing objects the way Hibernate does (I believe it invokes the 0-arg constructor and then it probably modifies the instance's fields directly via Reflection. Perhaps it knows how to call setters) goes a little bit against how is an object supposed to be constructed in Java- invoke the constructor with the appropriate parameters so that the new object is the object you want. I believe that instantiating an object and then mutating it is somewhat "anti-Java" (or I would say, anti pure theoretical Java)- and definitely, if you do this via direct field manipulation, it goes encapsulation and all that fancy encapsulation stuff.

I think that the proper way to do this would be to define in the Hibernate mapping how an object should be instantiated from the info in the database row using the proper constructor... but this would be more complex- meaning both Hibernate would be even more complex, the mapping would be more complex... and all to be more "pure"; and I don't think this would have an advantage over the current approach (other than feeling good about doing things "the proper way").

Having said that, and seeing that the Hibernate approach is not very "clean", the obligation to have a 0-arg constructor is not strictly necessary, but I can understand somewhat the requirement, although I believe they did it on purely "proper way" grounds, when they strayed from the "proper way" (albeit for reasonable reasons) much before that.

alex
+4  A: 

Let's suppose we have The following class

@Entity
public class Person {

    private Integer id;

    private String name;
    private Integer age;

    public Person(Integer id) {
        this.id = id;
    }

    public Person(String name, Integer age) {
        this.age = age;
        this.name = name;
    }

    // getter's and setter's

}

Now suppose you need to retrieve a stored Person object

Integer requiredPerson = 5;

Person person = (Person) session.get(Person.class, requiredPerson);

Think as a Software Engineer

Which constructor should i call to retrieve a Person object ???

Either

Person person = new Person(5);

Or

Person person = new Person(<WHICH_NAME_SHOULD_I_SET_UP>, <WHICH_AGE_SHOULD_I_SET_UP>);

And what happens whether your class contains a lot of contructors ???

keep in mind: There is no Hibernate annotation which points to a desired constructor

    @InstantiatePersonByUsingThis
    public Person(String name, Integer age) {
        this.age = age;
        this.name = name;
    }    

And reflection allows you instantiate a class Through its no-arg constructor. So when you call

Person person = (Person) session.get(Person.class, requiredPerson);

Hibernate will instantiate your Person object as follows

Person.class.newInstance();

Which according to API documentation

The class is instantiated as if by a new expression with an empty argument list

Moral of the story

Person.class.newInstance();

is similar To

new Person();

Nothing else

Arthur Ronald F D Garcia
A: 

It is much easier to create object with a parameterless constructor through reflection, and then fill its properties with data through reflection, than to try and match data to arbitrary parameters of a parameterized constructor, with changing names/naming conflicts, undefined logic inside constructor, parameter sets not matching properties of an object, et cetera.

Many ORMs and serializers require parameterless constructors, because paramterized constructors through reflection are very fragile, and parameterless constructors provide both stability to the application and control over the object behavior to the developer.

Kaerber