Spring: apply #Autowired to property to eliminate setter - java

My understanding about the #Autowired annotation applying on a property of a bean is that by doing that we can eliminate the setter method. This seems valid when we choose to annotation based configuration: we just create a bean annotated with #Component and annotate #Autowired to its property of interest.
However I failed to do the same when I tested the idea using xml based configuration.
Here is what I put in the bean class:
#Autowired
private String message2;
public String getMessage2() {
return message2;
}
In the xml file:
<bean id="testBean" class="TestBean">
<property name="message2" value="Hello world!"/>
</bean>
the IDE complained "can't resolve the property" and failed to compile. Maybe using #Autowired with xml configuration is an odd marriage that is disallowed?
Anyone care to help me on this might-be-silly question?

If you don't want the setter, then get rid of the <property> element in your TestBean bean definition. That property requires that a setter be available to set the property. Because it's missing, if you actually tried to load the XML configuration, with a ClassPathXmlApplicationContext for example, you'd get this error
Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property message2 of bean class [org.example.TestBean]: Bean property message2 is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
After removing <property>, declare an appropriate bean to inject
<bean id="message2" class="java.lang.String">
<constructor-arg value="Helllo world!"/>
</bean>
You'll also need
<context:annotation-config />
to register the AutowiredAnnotationBeanPostProcessor that handles processing of #Autowired.
Note that declaring a String bean is awkward. You'd be better served by using the <property> or some property resolution mechanism that pulls the value from a config file and assigns it through a #Value annotated field.
#Value("${config.message2}")
private String message2;

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!

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.

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.

spring3.0 annotations

I have a property file converterValues.properties having these data valueOne=1,valueTwo=2
i am trying to use the annotation
#Value("#{converterValues.valueOne}")
private transient String dataValue;
I want to load all the properties at once not each at a time using converterValues.valueOne
let me know how to get valueOne=1,valueTwo=2 at once using annotation.
I want to avoid defining #value for each key.
First create a qualifier annotation, let's call it #ConverterValues.
Then declare a bean of type PropertiesFactoryBean with the given qualifier.
<bean id="converterValues" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:path/to/properties" />
<qualifier value="your.package.ConverterValues" />
</bean>
Now you can inject the properties into your bean:
#Autowired
#ConverterValues
private Properties converterValues;
Update
You could, of course, skip the overhead of defining a qualifier if you are willing to express the dependency explicitly:
#Autowired
#Qualifier("converterValues") // the name of the bean to inject
private Properties converterValues;

Spring #Autowired with 2 beans of the same type

I have the following defined.
#Autowired
DaoType1<object1> someDao;
#Autowired
DaoType1<object1> someListDao;
and in my bean definitions I have two beans of the same type
<bean id="someDao" class="com.example.DaoType1" />
<bean id="someListDao" class="com.example.DaoType1" />
The second bean is imported from another xml file if that makes a difference. They have different properties being set as well. Why is spring not throwing an error because 2 beans of the same type have been defined. Does it use the variable names since they match the bean ids. The dao's are different and the functionality works as expected if I had used #Qualifiers for the two different beans.
Here is a more concise version. I've left out other beans since I they are not relevant.
applicationContext.xml
<import resource="classpath:dm-services-crud.xml"/>
<bean id="ruleListCrudService" class="com.idna.dm.service.crud.impl.RuleCrudServiceImpl">
<property name="crudDao" ref="ruleListCrudDao" />
</bean>
dm-services-crud.xml
<bean id="ruleCrudService" class="com.idna.dm.service.crud.impl.RuleCrudServiceImpl">
<property name="crudDao" ref="ruleCrudDao" />
<property name="ruleNetworkOfNodesCrudService" ref="ruleNetworkOfNodesCrudService" />
<property name="elementMappingsCrudService" ref="elementMappingsCrudService" />
<property name="ruleCrudDao" ref="newRuleCrudDao"/>
</bean>
default-autowire is not present in any of my xml files at all.
This appears to be expected behaviour. The documentation says:
byName
Autowiring by property name. Spring looks for a bean with the same name as the property that needs to be autowired. For example, if a bean definition is set to autowire by name, and it contains a master property (that is, it has a setMaster(..) method), Spring looks for a bean definition named master, and uses it to set the property.
I guess this means you have specified default-autowire="byName" in your applicationContext.xml.
However, refactoring may affect this in an unpredictable way. That's why (I think) it is advisable to switch to autowiring by type, and disambiguate the beans by the use of
#Qualifier (as you noted)
#Resource rather than #Autowired (as skaffman noted)
The #Autowired annotation behaves slightly differently to the "autowire by type" specification on xml based bean definitions.
When using annotations you're not technically doing an auto wire... you're setting the value based on the annotation. The autowire annotation has the same function as the xml property element.

Categories

Resources