I'm reading the JavaBean specification but I can't find a sentence where it clearly states that a bean must have a default constructor. So does it or doesn't?
The compiler doesn't ever enforce the existence of a default constructor. You can have any kind of constructor as you wish. For some libraries or frameworks it might be necessary for a class to have a default constructor, but that is not enforced by the compiler.
No, you are not required to use default (no arg) constructors.
Yes, Spring can invoke private constructors. If it finds a constructor with the right arguments, regardless of visibility, it will use reflection to set its constructor to be accessible.
We also call this as a special method of the class. In case we don't provide any constructor in the class, the compiler will create a default constructor for that particular class. So by default there will be one constructor of the class and it's mandatory.
You can look at the wikipedia about java bean:
https://en.wikipedia.org/wiki/JavaBeans
The bean should have a public default constructor is one of the rules for it qualifying as a JavaBean. However, this is not explicitly defined by the standard, but is a good practice adopted by many frameworks.
EDIT: If we were to elaborate about the reasons WHY a non-args constructor is desired (but generally not enforced), below is one of the reasons:
CDI frameworks generally have two way of injecting dependencies in your bean:
Constructor injection: Where you have defined explicitly the dependencies of your bean in its constructor. Example (Spring):
@Component
public class SuchBean {
private MuchDependency muchDependency;
@Autowired
public SuchBean(MuchDependency muchDependency){
this.muchDependency = muchDependency;
}
}
Setter/Reflection injection: Where you haven't necessarily injected any dependencies through the constructor, but the dependencies are injected by the CDI environment by either using reflection or the setters. Example:
@Component
public class SuchBean {
// this dep doesn't have a setter, so the CDI will use reflection to set it
@Autowired private MuchDependencyWithReflection muchDependencyWithReflection;
// this dep has a setter so the CDI will use the setter to set it
@Autowired private MuchDependencyWithSetter muchDependencyWithSetter;
public void setMuchDependencyWithSetter(MuchDependencyWithSetter muchDependencyWithSetter){
this.muchDependencyWithSetter = muchDependencyWithSetter;
}
}
In the above example, if you haven't explicitly defined the no-args constructor, of course, you know, Java provides it for you (cause every class that doesn't have any constructor explicitly defined, just has an automatically provided no-args constructor). So everything would be fine and dandy until you decide to define your own constructor with args:
@Component
public class SuchBean {
// this dep doesn't have a setter, so the CDI will use reflection to set it
@Autowired private MuchDependencyWithReflection muchDependencyWithReflection;
// this dep has a setter so the CDI will use the setter to set it
@Autowired private MuchDependencyWithSetter muchDependencyWithSetter;
public SuchBean(String nonDefaultConstuctorArg){
System.out.println(nonDefaultConstuctorArg);
}
public void setMuchDependencyWithSetter(MuchDependencyWithSetter muchDependencyWithSetter){
this.muchDependencyWithSetter = muchDependencyWithSetter;
}
}
In the above example it is not obvious, but any dependency framework would complain and won't be able to instantiate it, because in fact, when you are using reflection/setter injection, the framework does:
Constructor.newInstance();
behind the scenes AND then injects the dependencies. However, since you just made your class not have a default constructor, newInstance() without args wouldn't work. Hence, you need a default args constructor in this case. To summarize:
A bean does not need to have a default constructor. Simply because the spec does not define that requirement.
Additionally chapter 10.3 Instantiating a bean talks about obtaining bean instances:
A bean can be delivered as either a serialized template (which must be deserialized to create an instance of the bean) or as an implementation class (where a bean instance is created simply by creating an instance of the class).
This strategy is implemented by Beans.instantiate
: It looks for a serialized bean (a special named Java resource). If it doesn't find one it tries to instantiate the bean via Class.newInstance
. But this mechanism clearly shows that the spec writers thought about providing a generic method to get bean instances which do not have a default constructor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With