How setter works inside Spring Framework? - java

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!

Related

Spring bean get initialized twice by xml and component-scan

I have created few singleton bean in spring. I added log inside constructor. I could see log is getting printed twice.
#Component
public class User{
public User() {
System.out.println(" Bean got initialized"+this);
}
private Integer userid;
private String username;
//getter and setter
}
I have defined bean in XML and configured auto-scan.
<context:component-scan base-package="com.demo" />
<bean id="user" class="com.demo.User"/>
Since I have initialized bean in context xml and package scan, bean is getting initialized twice. After removing #Component from class, I am seeing only once log.
Please confirm my understanding is correct or not?
That's correct; the component scan will pick it up, and then you explicitly create another copy.
#Component annotation was introduced in spring 2.5 in order to get rid of XML bean definition by using classpath scanning. if the class is annotated with #Component, it will auto detected in the classpath scanning and an instance will be created(instantiated). Since #Component does the job for creating the bean, you do not have to declare the bean in XML. So remove the XML bean declaration. so it will not create duplicate objects.
Note: if you do the annotation based bean declaration with #Component, you do not need to use XML based declaration as you have done. If you are doing the XML based bean declaration, you do not need to do the annotation based bean declaration. So make sure that you declare only one of these options. not with both.

'Instantiation of bean failed; Is it an abstract class?' When trying to instantiate a bean with an abstract parent

I'm trying to instantiate a bean, without a class definition, on Spring context by inheriting a parent bean, which is abstract. Like this:
<bean id="childBean" parent="abstractBean">
...
</bean>
<bean id="abstractBean" class="com.java.bean.AbstractBeanClass"
abstract="true" />
But Spring is giving me the following error message:
Error creating bean with name 'childBean' defined in class path resource
[project-spring.xml]:
Instantiation of bean failed; nested exception is
org.springframework.beans.BeanInstantiationException:
Could not instantiate bean class [com.java.bean.AbstractBeanClass]:
Is it an abstract class?;
nested exception is java.lang.InstantiationException
...
I remember having this in another project, and it works perfectly.
I remember having this in the same project, and it works perfectly.
What am I missing here?
UPDATE 1
Found another bean being intatiated exactly like the way I mentioned:
<bean id="variantOptionDataConverter" parent="abstractPopulatingConverter">
...
</bean>
UPDATE 2
Declaration of the Abstract class:
public abstract class AbstractBeanClass<SOURCE, TARGET>
extends AbstractConverter<SOURCE, TARGET>
implements PopulatorList<SOURCE, TARGET>
{
...
}
Note: There's other classes that extends this class. None of the "other spring beans that works" I mentioned above extends this class.
Note 2: I know that it's weird, and, by Java fundamentals, it should not work (like everyone mentioned). But, I don't know how, the other Spring beans are being put in the context. I tried to copy the "other spring beans that work" into my code, change some duplicated names, and it worked. And, that's what I'm trying to understand...
This concrete example Juliano is referring to is from the hybris commerce suite.
Hybris has the concept of extensions that have dependencies on each other. Each extension defines their own application context which has access to its inherited application contexts (from those extensions that are declared as dependencies).
In this example there is an abstractPopulatingConverter bean declaration declared at the root application context where its declared java class is abstract.
However, in other application context further down the dependency tree there is an alias definition for this "abstractPopulatingConverter" that points to a bean definitions with a concrete class.
That's why in a lot of cases (namely the ones that are even further down the dependency tree) using the parent="abstractPopulatingConverter" works as it points to the new bean defined by the alias.
This is the very common message when Spring container faces with absatract Java class (not abstract bean). Check your com.java.bean.AbstractBeanClass code and probably you can find "public abstract class".
What am I missing here?
I don't know what's going on in your other project, but Spring cannot instantiate beans for classes that are abstract.
Concerning abstract beans, the Spring documentation states
A child bean definition inherits configuration data from a parent definition.
[...]
A child bean definition uses the bean class from the parent definition
if none is specified, but can also override it. In the latter case,
the child bean class must be compatible with the parent, that is, it
must accept the parent’s property values.
In other words, an bean definition declared with abstract="true" is simply used as a template for other beans.
Java does not allow instantiation of abstract classes. Spring cannot overrule this language feature. Spring cannot instantiate beans of abstract class types.
Found the answer:
Indeed, like Sotirios Delimanolis commented, "You must have something else going on, proxying of some kind maybe", Spring has a proxy that instantiate this type of bean declaration, but it can't instantiate the bean without its methods (which are just declared in the abstract class, not implemented).
So you must "implement" these methods, like this:
<bean id="childBean" parent="abstractBean">
<lookup-method name="notImplementedMethod" bean="anotherBean"/>
</bean>
The anotherBean must be the same type as notImplementedMethod.

Spring: Xml based Autowiring a list of beans by interface type

With Spring it is possible to inject a list of beans by the interface class like:
#Component
public class Service {
#Autowire
private List<InterfaceType> implementingBeans;
...
}
All defined beans that implement this interface will be present in this List.
The annotation based approach is not possible for me, as the Service class is in a module that must not have spring dependencies.
I need to use this mechanism from outside via xml configuration.
<bean id="service" class="...Service">
<property name="implementingBeans">
??? tell spring to create a list bean that resolves all beans of the interfaceType.
</property>
</bean>
Does anyone know how to solve this?
EDIT: Additionally, there are more than one spring applications that use this service. So the best solution would be to handle this szenario completely via xml configuration. I can then copy the xml parts to all spriong applications that need this.
I want to avoid having a kind of initializer bean that gets the service injected and must then be copied to all spring applications.
Kind regards.
An XML-only solution would simply have you declare a <bean> of the "external" type and provide an autowire value of "byType".
Controls whether bean properties are "autowired". This is an
automagical process in which bean references don't need to be coded
explicitly in the XML bean definition file, but rather the Spring
container works out dependencies.
[...]
"byType" Autowiring if there is exactly one bean of the property type in the container. If there is more than one, a fatal error is
raised, and you cannot use byType autowiring for that bean. If there
is none, nothing special happens.
The explanation is a little confusing in that we expect multiple InterfaceType beans, but the actual field is of type List and Spring will be able to dynamically instantiate one and add all the InterfaceType beans to it, then inject it.
Your XML would simply look like
<bean id="service" class="...Service" autowire="byType">
</bean>
My original suggested solution made use of SpEL.
In the module that does have Spring dependencies, create a DTO
#Component(value = "beanDTO")
public class BeanDTO {
#Autowire
private List<InterfaceType> implementingBeans;
public List<InterfaceType> getImplementingBeans() {
return implementingBeans;
}
}
and then use SpEL to retrieve the value of implementingBeans from the beanDTO bean.
<bean id="service" depends-on="beanDTO" class="...Service">
<property name="implementingBeans" value="{beanDTO.implementingBeans}" />
</bean>
Spring will create the BeanTDO bean, inject all the beans that are of type InterfaceType. It will then create the service bean and set its property from beanDTO's implementingBeans property.
Following comments on question:
In an effort to be more JSR 330 compliant, Spring has introduced support for Java EE's javax.inject package. You can now annotate your injection targets with #javax.inject.Inject instead of #Autowired. Similarly, you can use #Named instead of #Component. The documentation has more details.

Set a public variable of bean in spring without using a setter

I read on a few websites that with Spring its possible to do setter based Dependency Injection without having to create a setter for the injected variable it. Would nicely tidy up the code. I read this on another site and also here on stackoverflow.
I've tried it but in my case it does not work. I'm using 3.2.0.RELEASE. I'm getting the following error.
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'DI_without_setter' defined in class path resource [SpringBeans.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'url' of bean class [net.comsys.springpropstest.DiWithoutSetter]: Bean property 'url' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
my Java test code
package net.xxx.springpropstest;
public class DiWithoutSetter {
private String url;
}
I've just added it to my main code. Not displayed here. I don't even use DiWithoutSetter in the main code.
SpringBeans.xml
<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-3.0.xsd">
<bean id="DI_without_setter" class="net.xxx.springpropstest.DiWithoutSetter">
<property name="url" value="jan" />
</bean>
If someone could shed some light on his issue that would be appreciated. Is it possible to set the value of a (public) variable in a Spring bean without using a setter method?
You can't do that (you need a setter), and that tutorial appears to be wrong (note in the example source zip, the classes have getters and setters).
Either add a setter or #Inject the field implicitly using autowiring.
You would need to annotate the field with #Autowired and enable component scanning for this injection to work without a setter method.

Does Spring require all beans to have a default constructor?

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.

Categories

Resources