Does Spring require all beans to have a default constructor? - java

I don't want to create a default constructor for my auditRecord class.
But Spring seems to insist on it:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'auditRecord' defined in ServletContext resource
[/WEB-INF/applicationContext.xml]:
Instantiation of bean failed;
nested exception is org.springframework.beans.BeanInstantiationException:
Could not instantiate bean class [com.bartholem.AuditRecord]:
No default constructor found;
nested exception is
java.security.PrivilegedActionException:
java.lang.NoSuchMethodException:
com.bartholem.AuditRecord
Is this really necessary?

No, you are not required to use default (no arg) constructors.
How did you define your bean? It sounds like you may have told Spring to instantiate your bean something like one of these:
<bean id="AuditRecord" class="com.bartholem.AuditRecord"/>
<bean id="AnotherAuditRecord" class="com.bartholem.AuditRecord">
<property name="someProperty" val="someVal"/>
</bean>
Where you did not provide a constructor argument. The previous will use default (or no arg) constructors. If you want to use a constructor that takes in arguments, you need to specify them with the constructor-arg element like so:
<bean id="AnotherAuditRecord" class="com.bartholem.AuditRecord">
<constructor-arg val="someVal"/>
</bean>
If you want to reference another bean in your application context, you can do it using the ref attribute of the constructor-arg element rather than the val attribute.
<bean id="AnotherAuditRecord" class="com.bartholem.AuditRecord">
<constructor-arg ref="AnotherBean"/>
</bean>
<bean id="AnotherBean" class="some.other.Class" />

nicholas' answer is right on the money for XML configuration. I'd just like to point out that when using annotations to configure your beans, it's not only simpler to do constructor injection, it's a much more natural way to do it:
class Foo {
private SomeDependency someDependency;
private OtherDependency otherDependency;
#Autowired
public Foo(SomeDependency someDependency, OtherDependency otherDependency) {
this.someDependency = someDependency;
this.otherDependency = otherDependency;
}
}

You might be able to do constructor based injection, i.e. something like this (taken from documentation found here)
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
</bean>
but I'm not sure it will work.
If you are defining a JavaBean, you need to follow the convention and put a public no-arg constructor on it.

Almost all Java developers know that compiler adds a default constructor or better known as a no-argument constructor in every Java class, but many of them forget that it only does when you don't provide any other constructor. This means it becomes the developers' responsibility to add a no-argument constructor if he is adding explicit constructor. Now, Why it's important to provide default constructor in Java, What happens if your class doesn't have a no-argument constructor? Well, this is how it's asked in many Java interviews, most commonly as part of Spring and Hibernate interviews.
You should always define a no argument constructor in your Java class, even if you are writing an explicitly constructor, until you are absolutely sure that, it's won't be instantiated using reflection and instantiating it with no argument constructor is a bug, like in your example of Spring Bean.

Related

How setter works inside Spring Framework?

I'm new in spring Framework. And actually i was doing an experiment with spring actually.
Look at this HelloWorld.java:
public class HelloWorld {
private String messageee;
public void setMessage(String messageee){
this.messageee=messageee;
}
public void show(){
System.out.println("message: "+messageee);
}
}
You see in this program, I've one variable which is outside declared as private named as messageee and next variable which is parametrized with setter named as messageee. You see both have same name.
Okay.. Now look at this bean file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="helloWorld" class="com.springframework.HelloWorld">
<property name="message" value="Hello.. This is Spring Framework example."></property>
</bean>
</beans>
Here you see inside bean tag. I've declared the property name as message. I don't understand, when i give the name as messageee it gives an error as:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'helloWorld' defined in class path resource [beans.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'messageee' of bean class [com.springframework.HelloWorld]: Bean property 'messageee' is not writable or has an invalid setter method. Did you mean 'message'?
But when i give the name as message. It runs successfully. But i don't have any message's method or any kind of variables with this similar name. So, How setter works actually? Will you please elaborate?
Help would be appreciated!
You're confusing fields (or instance variables) with properties.
property is a term coming from the Java Beans specification. A property foo of a bean is data that can be accessed using a getter method called getFoo() (or isFoo() for a boolean) and/or set using a setter method called setFoo().
What these methods do internally, whether they get/set a variable or not, whether the variable is also named foo or anything else, is completely irrelevant. What matters is the name of the getter/setter.
So, when you define your bean and tell Spring to set the property named message, Spring will look for a method called setMessage(). It doesn't care about the private fields of your bean class.
The Spring IoC container also supports setter injection, which is the preferred method of dependency injection in Spring. Setter injection uses the set* methods in a class file to garner property names that are configurable in the spring XML config.
From a configuration standpoint, setter injection is easier to read because the property name being set is assigned as an attribute to the bean, along with the value being injected.
To determine the property names, Spring follows the JavaBeans Specification.
First of all, you are mixing up fields with properties - also your property name in the applicationContext.xml is wrong (it should be messageee)
You need to use #Autowired annotation with either:
1) fields i.e. messageee
or
2) setter i.e. setMessage()
If you are thinking "what is that!!???" Read about Spring's basic features with beans and how Spring is capable of taking POJOs (Plain Old Java Objects) to and configure them using the IoC framework. Read about #Autowired here - How does autowiring work in Spring?
Then you should be fine with this:
<bean id="helloWorld" class="com.springframework.HelloWorld">
<property name="message" value="Hello.. This is Spring Framework example."></property>
</bean>
BTW...good approach for looking into Spring by using the very basic Java stuff....good luck!

How to autowire a class with non-empty constructor?

I'd like to #Autowired a class that has a non-empty constructor.
Just the the following as an example, it does not necessairly have to be a view/service. Could be whatever component you like, having non-default constructor:
#Component
class MyViewService {
//the "datasource" to show in the view
private List<String> companies companies;
private MyObject obj;
public MyViewService(List<String> companies, MyObject obj) {
this.companies = companies;
this.obj = obj;
}
}
Of course I cannot just write
#Autowired
private MyViewService viewService;
as I'd like to use the constructor with the list. But how?
Are there better approaches than refactoring these sort of constructors to setters? I wouldn't like this approach as ideally the constructor forces other classes to provide all objects that are needed within the service. If I use setters, one could easily forget to set certain objects.
If you want Spring to manage MyViewService you have to tell Spring how to create an instance of it. If you're using XML configuration:
<bean id="myViewService" class="org.membersound.MyViewService">
<constructor-arg index="0" ref="ref_to_list" />
<constructor-arg index="1" ref="ref_to_object" />
</bean>
If you're using Java configuration then you'd call the constructor yourself in your #Beanannotated method.
Check out the Spring docs on this topic. To address a comment you made to another answer, you can create a List bean in XML as shown in the Spring docs. If the list data isn't fixed (which it's probably not) then you want to use an instance factory method to instantiate the bean.
In short, the answers you seek are all in the Spring docs :)
If a component has a non-default constructor then you need to configure the constructor in the bean configuration.
If you are using XML,
it might look like this (example from the spring reference document):
<beans>
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
</bean>
<bean id="bar" class="x.y.Bar"/>
<bean id="baz" class="x.y.Baz"/>
</beans>
The key here is constructor wiring of the bean that will be used for the #AutoWire.
The way you use the bean has no impact.

Spring throws the error: Bean definition is abstract

I need some help with next topic.
I have a hierarchy of beans, just like that:
<bean id="father" class="myPackage.Father" abstract="true"/>
<bean id="childA" class="myPackage.ChildA" parent="father">
<property name="atrib1" value="hello"></property>
</bean>
<bean id="childB" class="myPackage.ChildB" parent="father">
<property name="atrib2" value="bye"></property>
<property name="atrib3" value="other"></property>
</bean>
I need to create another bean which contains a reference to the abstract class. Then at run-time, I will need to be able to initialize a variable of TYPE "myPackage.Father" and instantiate it with any of the children classes (the polymorphism mechanism). I mean something like that:
<bean id="reference" class="myPackage.Another">
<property name="atrib4" ref="father"></property>
</bean>
Note that reference (an instance of myPackage.Another) is not a subclass of myPackage.Father. But with these lines Spring throws the next error:
Bean definition is abstract
How could I deal with it?
I appreciate any help, thanks in advance!
abstract beans are never instantiated as objects, they exist only in the form of definitions.
From the documention:http://docs.spring.io/spring/docs/3.0.x/reference/beans.html
The parent bean cannot be instantiated on its own because it is incomplete, and it is also explicitly marked as abstract. When a definition is abstract like this, it is usable only as a pure template bean definition that serves as a parent definition for child definitions. Trying to use such an abstract parent bean on its own, by referring to it as a ref property of another bean or doing an explicit getBean() call with the parent bean id, returns an error. Similarly, the container's internal preInstantiateSingletons() method ignores bean definitions that are defined as abstract.
In your case
<bean id="reference" class="myPackage.Another">
<property name="atrib4" ref="father"></property>
</bean>
is refering to the bean defined as abstract which is causing the issue.
First of all abstract bean has nothing to do with the abstract class
they don't even need to be mapped to a class.They are used to group the common properties shared by another beans.But you can not use an abstract bean as a ref to wire a property in another bean.
If your bean myPackage.Another has a reference of type myPackage.Father and your child beans are assignable (either extends of implements) to myPackage.Father then you can wire either childA or childB
in your myPackage.Another bean like this
<bean id="reference" class="myPackage.Another">
<property name="atrib4" ref="childA"></property>
</bean>
There is no different between abstract class and abstract beans.When you use beans and refer to another bean which is abstract , it means you want to instantiate an abstract class it and it can not work surely !
Be careful when you are using an abstract class ! An abstract class is used for template class and you can just extend it !

How do you inject a proxy into a service?

There is some information in the tomcat engine that we want to access run time, so we have the following in our app context (got this from this blog post):
<bean id="tomcatEngineProxy" class="org.springframework.jmx.access.MBeanProxyFactoryBean">
<property name="objectName" value="Catalina:type=Engine" />
<property name="proxyInterface" value="org.apache.catalina.Engine" />
<property name="useStrictCasing" value="false" />
</bean>
In a controller, we then autowired it in like this:
#Autowired
private MBeanProxyFactoryBean tomcatEngineProxy = null;
We cannot wire in org.apache.catalina.Engine like in the blog post, because that class is not available to us at build time. It's only available at run time with all the different tomcat versions running on the different machines.
We were able to get the information we needed from this #Autowire using reflection. Now, we want to move this functionality into a service. I added this to our app context:
<bean id="myService" class="com.foo.bar.MyServiceImpl">
<constructor-arg ref="tomcatEngineProxy" />
</bean>
And the class looks like this:
public class MyServiceImpl implements MyService
{
public MyServiceImpl(MBeanProxyFactoryBean tomcatEngineProxy) throws Exception
{
//stuff with the proxy
}
.....
}
When I do this, I get the following error:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myService' defined in ServletContext resource [/WEB-INF/spring/root-context.xml]: Unsatisfied dependency expressed through constructor argument with index 0 of type [org.springframework.jmx.access.MBeanProxyFactoryBean]: Could not convert constructor argument value of type [$Proxy44] to required type [org.springframework.jmx.access.MBeanProxyFactoryBean]: Failed to convert value of type '$Proxy44 implementing org.apache.catalina.Engine,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised' to required type 'org.springframework.jmx.access.MBeanProxyFactoryBean'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [$Proxy44 implementing org.apache.catalina.Engine,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [org.springframework.jmx.access.MBeanProxyFactoryBean]: no matching editors or conversion strategy found
Knowing basically nothing about how proxies work and how to use them, I'm not sure how to go about making this work. Is there some declaration I can use for my constructor arg that will match up? What is different between the #Autowire in the controller that does work and the constructor arg that doesn't work?
It's because your factory bean is exposing the result as the engine interface:
<property name="proxyInterface" value="org.apache.catalina.Engine" />
So if you try to wire in the "tomcatEngineProxy" bean itself, it's only compatible assignment is to "org.apache.catalina.Engine", since the created proxy implements only that interface.
try referencing the factory bean directly instead (notice the ampersand which is the syntax for finding the actual factory bean which created the object instead of the object itself):
<constructor-arg ref="&tomcatEngineProxy" />
How to inject FactoryBean instead of object it produces?
I believe that #Autowired works since the binding is done according to the type of the Bean (i.e. MBeanProxyFactoryBean), however the binding to the constructor argument is done by name and the name you provided tomcatEngineProxy does not match the type you expect since the type of a bean created using a FactoryBean is different than that of the FactoryBean.
It looks like the simplest solution will be to change MyServiceImpl to be:
public class MyServiceImpl implements MyService
{
#Autowired
private MBeanProxyFactoryBean tomcatEngineProxy;
public MyServiceImpl() throws Exception
{
//stuff with the proxy
}
.....
}
This should do the trick.

Spring and passing parameters to factory-method in runtime

The documentation of method context.getBean(name, user) says
Allows for specifying explicit constructor arguments / factory method
arguments
but no matter what I do (tried everything), with the most logical setting I get this when the beans are being loaded up during initialization:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'fileValidator' defined in
PortletContext resource
[/WEB-INF/classes/context/customer-form-portlet.xml]: Unsatisfied
dependency expressed through constructor argument with index 0 of type
[com.liferay.portal.model.User]: Ambiguous factory method argument
types - did you specify the correct bean references as factory method
arguments?
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'fileValidator' defined in
PortletContext resource
[/WEB-INF/classes/context/customer-form-portlet.xml]: Unsatisfied
dependency expressed through constructor argument with index 0 of type
[com.liferay.portal.model.User]: Ambiguous factory method argument
types - did you specify the correct bean references as factory method
arguments?
<bean id="fileValidator"
class="cz.instance.transl.validation.file.FileValidator"
factory-method="createInstance" />
private FileValidator(User user) {
this.user = user;
}
public static FileValidator createInstance(User user) {
return new FileValidator(user);
}
The commentary says you can do it, but if you specify constructor arguments in xml definiton of that bean or not, it fails.
The javadoc says:
args - arguments to use if creating a prototype using explicit arguments to a static factory method.
So the bean definition must be a prototype-scoped bean, i.e.
<bean id="fileValidator"
scope="prototype"
class="cz.instance.transl.validation.file.FileValidator"
factory-method="createInstance" />
Reading across 20 posts, I found that it was not apparent how to get a custom factory method to take parameters at run-time, especially since we are forced to use the constructor-arg tags and refer to an existing bean in the context as setup below and the class in question acting as a static factory method.
<bean id="user" class="something.something.User" />
<bean id="fileValidator"
class="cz.instance.transl.validation.file.FileValidator"
factory-method="createInstance" >
<constructor-args ref="user" />
</bean>
I got it working by fetching an instance of the bean used in the constructor-arg out of the context and then populating it with the values that you are working with at run-time. This bean will then be used as the parameter when you get your factory-generated bean.
public class X {
public void callFactoryAndGetNewInstance() {
User user = context.getBean("user");
user.setSomethingUsefull(...);
FileValidator validator = (FileValidator)context.getBean("fileValidator");
...
}
}
Note this doesn't solve the problem asked of using context.getBean(arg1, arg2) as that method isn't relevant in this scenario. The reason it isn't is because all these beans are singleton and at this point the constructor isn't invoked. Not a problem and not anything to care about if you are working in a single-user system as you only have 1 User bean in your context at any time anyhow!
However, For a multi-user system you will need to make sure that you have a unique User bean for each real user and that you use the correct User bean in the factory method invocation.
In order to do this in a multi-user system, you will need to change the bean types to be prototype AND you should create a bean of your FileValidator that represents the factory (if you plan to dependency injection into the factory) and another bean FileValidator that represents your new instance. They will both be of the same class type but you must give each one a unique name. See below:
<bean id="user" scope="prototype" class="something.something.User" />
<bean id="validatorFactory"
class="cz.instance.transl.validation.file.FileValidator">
<constructor-arg value="something" />
</bean>
<bean id="fileValidatorBean"
class="cz.instance.transl.validation.file.FileValidator"
scope="prototype"
factory-method="createInstance" >
<constructor-arg ref="user" />
</bean>
and in the class where you would like to get this new FileValidator bean from the factory, you can use the technique below:
public void someMethod() {
...
User user = context.getBean("user");
user.setSomethingUsefull(...);
FileValidator fileValidator =
(FileValidator)context.getBean("fileValidatorBean",
user);
...
}
In order to call your factory method Spring needs access to a user instance to pass to createInstance. In this case I am just creating a bean and passing it in:
<bean id="user" class="something.something.User">
</bean>
<bean id="validator" class="cz.instance.transl.validation.file.FileValidator" factory-method="createInstance">
<constructor-arg ref="user"/>
</bean>
You can use an abstract factory too setting the factory-bean attribute. Here we have an ActionFactory which create actions.
<bean id="actions_factory" class="com.imagina.control.actions.impl.ActionFactoryImpl"/>
<bean id="load_person_action" class="com.imagina.control.actions.impl.LoadPersonAction"
factory-bean="actions_factory" factory-method="create">
<constructor-arg value="load_person_action"/>
</bean>
To use this configuration you have to take this points in account:
create method is not static. Now belongs to an instance
constructor-arg is the parameter of factory method

Categories

Resources