A simple test Shopping Application where i have two classes Clothing and Offers.
Now on calling formalshirt bean, it throws the following exception
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'DiwaliOffer' defined in class path resource [spring.xml]: Instantiation of bean failed;
nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [Offers]: No default constructor found;
nested exception is java.lang.NoSuchMethodException: Offers.<init>()
Now if i comment the Offers constructor, the app runs successfully. My query is Why does Spring looks for default constructor only when there is another constructor?
Clothing Class
public class Clothing {
private int price;
private List<Offers> offer;
public void setOffer(List<Offers> offer) {
this.offer = offer;
}
public void setPrice(int price) {
this.price = price;
}
}
.
Offers Class
public class Offers {
private int discount;
private String promocode;
public Offers(int val1, String val2)
{
this.discount=val1;
this.promocode=val2;
}
//public Offers(){} /*Default Constructor added due to Spring Exception as in below */
/* Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class No default constructor found */
/* Caused by: java.lang.NoSuchMethodException: com.test.Shopping.Offers.<init>() */
public void setDiscount(int discount) {
this.discount = discount;
}
public void setPromocode(String promocode) {
this.promocode = promocode;
}
}
Spring.xml
<bean id="formalshirt" class="com.test.Shopping.Clothing">
<property name="price" value="800"></property>
<property name="offer">
<list>
<ref bean="DiwaliOffer" />
</list>
</property>
</bean>
<bean id="DiwaliOffer" class="com.test.Shopping.Offers">
<property name="discount" value="10"></property>
<property name="promocode" value="diwali"></property>
</bean>
You need to change your Spring XML configuration of Offers to:
<bean id="DiwaliOffer" class="com.test.Shopping.Offers">
<constructor-arg value="10"></constructor-arg>
<constructor-arg value="diwali"></constructor-arg>
</bean>
The way you have configured it, Spring first attempts to call the default constructor and then call the setters. But of course there is no default constructor, and there fore Spring reports the exception.
Another option if you are using Spring 3+ is to use Java Config, instead of XML config.
You would just have
#Configuration
public class AppConfig {
//add other beans
#Bean
public Offers DiwaliOffer() {
return new Offers(10, diwali);
}
}
In your case Java Config has the benefit that your configuration would not even compile if you didn't call the constructor, ie. it would fail early instead of fail late as with the XML configuration
Spring is extremely flexible with how it creates beans, but you need to declare how it will be done
You need to use constructor-args for your bean properties so that it picks the non-default constructor. Otherwise Spring creates the object first, and without any parameters, it must use the zero-arg constructor, then sets properties with setters.
To pass in constructor args, change property to constructor-arg like so:
<bean id="DiwaliOffer" class="com.test.Shopping.Offers">
<constructor-arg index="0" value="10"/>
<constructor-arg index="1" value="diwali" />
</bean>
This is because when you add parametrize constructor, you need to tell spring to intanitate by giving constructor argument...
The concept is straight forward:
in default constriuctor case you will simply create object like new Test();
where as when you don't have default rather have parameterize constructor you have to create object like new Test1("test");
Class Test{
}
Class Test1{
Test1(String a){
}
}
Spring way will be:
<bean id="test1" class="Test1">
<constructor-arg value="Zara"/>
</bean
Please have look at Spring Doc for more details
If there are any constructor available in the class then java compiler does not provide default constructor.
And we can see com.test.Shopping.Clothing can able to create instance and com.test.Shopping.Offers can't.
To create the instance you need to pass constructor-arg of discount and promocode.
<bean id="DiwaliOffer" class="com.test.Shopping.Offers">
<constructor-arg value="10"></property>
<constructor-arg value="diwali"></property>
</bean>
You can do :
<bean id="DiwaliOffer" class="com.test.Shopping.Offers" >
<constructor-arg type="int" value="10" />
<constructor-arg type="java.lang.String" value="Diwali"/>
</bean>
The constructor-arg element within the bean element is used to set the property value thru constructor injection. Since there is only one constructor in the User bean class, this code will work fine.
Related
I'm migrating a Couchbase cache manager configuration from our legacy xml to a Java Config.
But I'm getting a java.lang.ClassCastException: com.sun.proxy.$Proxy219 cannot be cast to atorrico.cache.CouchbaseCache.
This is the XML file
<context:annotation-config />
<cache:annotation-driven />
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<ref local="mainCache" />
</set>
</property>
</bean>
<bean id="mainCache" class="atorrico.cache.CouchbaseCache" destroy-method="shutdown">
<constructor-arg index="0" value="${cache.main.name}" />
<constructor-arg index="1" value="${cache.servers}" />
<constructor-arg index="2" value="${cache.main.bucket.name}" />
<constructor-arg index="3" value="${cache.main.bucket.password}" />
<constructor-arg index="4" ref="couchbaseJaxb2Transcoder" />
<constructor-arg index="5" value="${cache.main.ttl}" />
<property name="operationTimeoutMillis" value="${cache.main.operationTimeoutMillis}" />
<property name="clientResetIntervalSeconds" value="${cache.main.clientResetIntervalSeconds}" />
<property name="enabled" value="${cache.main.enabled}" />
</bean>
<bean id="couchbaseJaxb2Transcoder" class="atorrico.couchbase.CouchbaseJaxb2Transcoder">
<property name="marshaller" ref="cacheJaxb2Marshaller" />
</bean>
<bean id="cacheJaxb2Marshaller" class="atorrico.couchbase.TweakedJaxb2Marshaller">
<property name="contextPath"
value="${cache.main.contextPath}" />
</bean>
This is the Java Config file
#Configuration
#EnableCaching
#EnableMBeanExport
public class CacheConfiguration {
#Value("${cache.main.name}")
private String mainCacheName;
#Value("${cache.servers}")
private String mainCacheServers;
#Value("${cache.main.bucket.name}")
private String mainCacheBucketName;
#Value("${cache.main.bucket.password}")
private String mainCacheBucketPassword;
#Value("${cache.main.ttl}")
private Integer mainCacheTtl;
#Value("${cache.main.operationTimeoutMillis}")
private Integer mainCacheOperationTimeoutMillis;
#Value("${cache.main.clientResetIntervalSeconds : -1}")
private Integer mainClientResetIntervalSeconds;
#Value("${cache.main.enabled}")
private Boolean mainCacheEnabled;
#Value("${cache.main.operation.queue.length : -1}")
private Integer mainCacheOperationQueueLength;
#Value("${cache.main.contextPath}")
private Integer mainCacheContextPath;
#Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(mainCouchbaseCache()));
return cacheManager;
}
#Bean(name = "mainCache", destroyMethod = "shutdown")
#Qualifier("mainCache")
public CouchbaseCache mainCouchbaseCache() {
CouchbaseCache couchbaseClient = new CouchbaseCache(mainCacheName, mainCacheServers, mainCacheBucketName, mainCacheBucketPassword,
mainCouchbaseJaxb2Transcoder(), mainCacheTtl);
couchbaseClient.setOperationTimeoutMillis(mainCacheOperationTimeoutMillis);
couchbaseClient.setClientResetIntervalSeconds(mainClientResetIntervalSeconds);
couchbaseClient.setEnabled(mainCacheEnabled);
couchbaseClient.setOperationQueueLength(mainCacheOperationQueueLength);
return couchbaseClient;
}
#Bean(name = "mainCouchbaseJaxb2Transcoder")
public CouchbaseJaxb2Transcoder mainCouchbaseJaxb2Transcoder() {
CouchbaseJaxb2Transcoder couchbaseJaxb2Transcoder = new CouchbaseJaxb2Transcoder();
couchbaseJaxb2Transcoder.setMarshaller(mainJaxb2Marshaller());
return couchbaseJaxb2Transcoder;
}
#Bean(name = "mainJaxb2Marshaller")
public TweakedJaxb2Marshaller mainJaxb2Marshaller() {
TweakedJaxb2Marshaller txStoreJaxb2Marshaller = new TweakedJaxb2Marshaller();
txStoreJaxb2Marshaller.setContextPath(mainCacheContextPath);
return txStoreJaxb2Marshaller;
}
I think the only difference between both version is that in the xml I have a
<ref local="mainCache" />
Note the use of local instead bean.
This is the hierarchy of java classes for the Couchbase client.
public interface CouchbaseClient {
....
}
public interface CouchbaseClientManagement {
....
}
public class CouchbaseClientImpl implements CouchbaseClient, CouchbaseClientManagement {
.....
}
public class CouchbaseCache extends CouchbaseClientImpl implements Cache, CouchbaseClientManagement {
....
}
This is the trace
Caused by: java.lang.ClassCastException: com.sun.proxy.$Proxy219 cannot be cast to atorrico.cache.CouchbaseCache
at atorrico.cache.configuration.CacheConfiguration$$EnhancerBySpringCGLIB$$dd4e20b8.mainCouchbaseCache(<generated>)
at atorrico.cache.configuration.CacheConfiguration.cacheManager(CacheConfiguration.java:76)
at atorrico.cache.configuration.CacheConfiguration$$EnhancerBySpringCGLIB$$dd4e20b8.CGLIB$cacheManager$0(<generated>)
at atorrico.cache.configuration.CacheConfiguration$$EnhancerBySpringCGLIB$$dd4e20b8$$FastClassBySpringCGLIB$$a8a6f2da.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:309)
at atorrico.cache.configuration.CacheConfiguration$$EnhancerBySpringCGLIB$$dd4e20b8.cacheManager(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
... 67 more
Why is this failing with Java Config but working fine with the XML config?
Can anyone find out what's going on here?
Thanks!
Spring has enhanced your CacheConfiguration class with some extra byte code. It's probably done this by creating a proxy that is a subclass of CacheConfiguration. You can see this in your stack trace as the class CacheConfiguration$$EnhancerBySpringCGLIB$$dd4e20b8.
When Spring instantiates the CacheManager, it first calls down through the cacheManager method it generated in the subclass, then calls your original cacheManager method, which calls the mainCouchbaseCache method.
Here's where it starts to get interesting. Your cacheManager method invokes not your mainCouchbaseCache method, but rather the generated one in the subclass. The generated method calls your mainCouchbaseCache, and your method generates the CouchbaseCache object and returns it. After your method returns, control returns to the generated subclass, which then wraps the returned CouchbaseCache in a generated proxy.
I'm not sure why Spring is generating the proxy, but for some reason it's decided that it needs to intercept calls to the methods of CouchbaseCache.
The problem is that because CouchbaseCache implements some interfaces, Spring creates a JDK dynamic proxy, and a limitation of JDK dynamic proxies is that they can only implement interfaces, not extend classes. (They extend java.lang.reflect.Proxy.) So the value that your cacheManager method sees returned from the mainCouchbaseCache method is not an instance of CouchbaseCache but rather an instance of some subclass of java.lang.reflect.Proxy that implements the Cache and CouchbaseClientManagement interfaces.
This works with the XML bean file because there is no Spring-generated proxy messing with the return value of the mainCouchbaseCache method.
I think you can fix this just by making mainCouchbaseCache return Cache instead of CouchbaseCache. Then at compile time Arrays.asList will expect a Cache array instead of a CouchbaseCache array, and since the returned proxy will implement Cache, everything will work.
Or you can tell Spring to not use a JDK dynamic proxy; see the Spring documentation on how it generates proxies. I think you want to use proxy-target-class=true, which will tell Spring to use CGLIB to generate an actual subclass CouchbaseCache.
I have a Spring 4 app with hibernate-validator on the classpath. I have a bean class which uses some javax validation annotations for the bean properties and I have another class that accepts that bean in it's constructor.
Java:
public class Config {
#NotNull
#Size(min=10)
public final String test;
#Min(5)
public final int num;
public Config(String test, int num) {
this.test = test;
this.num = num;
}
//getters
}
public class Test {
private Config config;
public Test(#Valid Config config) {
this.config = config;
}
}
My Spring application context is as follows:
<bean id="config" class="com.Config">
<constructor-arg type="java.lang.String">
<value>aaaa</value>
</constructor-arg>
<constructor-arg type="int">
<value>2</value>
</constructor-arg>
</bean>
<bean id="test" class="com.Test">
<constructor-arg ref="config" />
</bean>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
Note that the validator is defined in the application context. When I run the app as is, I expect an exception to be thrown when the bean is set into the test class constructor because the two arguments do not meet the constraints, but it runs without any exception. Am I missing something else?
The #Valid annotation is meant to be used for Controller methods, so it's not being evaluated here in your constructor.
This old question indicates how you can test the #Valid annotation by exposing and calling a Controller using Spring MVC. Also, if you notice other annotations are not working, make sure you have <mvc:annotation-driven /> somewhere in your context file.
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.
I got the following bean declearation in my [servlet-name]-servlet.xml of my Dynamic Web Project using Spring Web MVC?
I have read quite a lot of documents but stil couldnt understand what is the purpose of having those property tags?
<bean name="abcController" parent="defController"
class="abcController">
<constructor-arg ref="staticService" />
<property name="commandClass" value="abcCommand" />
<property name="property2" value="search" />
<property name="property3" value="true" />
<property name="formView" value="/someValue" />
</bean>
I know that the property could a field in abcController class, but there is no such a field named formView in abcController class!
Does anyone could help me out?
That xml file is used to create fields without having those fields coded in the file itself.
// This is used to Start the ApplicationContext Container and to get the Bean of AbcCotroller
ApplicationContext context =
new ClassPathXmlApplicationContext("[servlet-name]-servlet.xml");
abcController obj = (abcController) context.getBean("abcController");
You could later on use the beans in your code:
obj.getFormView(); //this will return '/somevalue'
//Bean.java
public class SampleBean{
private String message;
public void setMessage(String message){
this.message=message; //setter injection
}
public void ShowMessage(){
system.out.println("Message"+message);
}
}
//Main.java
Class Main{
public Static Void Main(String args[]){
//TO Start the ApplicationContext container
ApplicationContext applicationcontext = new ClassPathXmlApplicationCOntext("Spring.xml");
//To Read the SampleBean
Object o=applicationcontext .getBean("SampleBean");
SampleBean sampleBean=(SampleBean)o;
//Invoke the Method
sampleBean.ShowMessage();
}
}
//Spring.Xml
// you need to configure some more nameSpace which are required for Spring and Xml
<bean id="sampleBean" class="SampleBean">
<property name="message" value="this is the use of property Tag"/>
</bean>
//output :This is the use or Property Tag
explanation: when we want to perform Setter Injection we go for the Property
Tag
In spring we have some dependency injections like setter,constructor,interface,lookup method injection
when we use the Setter Injection first Dependent class object is create and next the dependency class object is created
Within Spring DI, can you "use" your bean within it's own definition? For example, if I have a bean called getTest1 with an inner bean declared within it, can I pass getTest1 to the constructor of that inner bean?
I'm wondering if I can implement a decorator patter-like solution using Spring DI for a work project but don't have much time to play around with it. Thanks!
Haven't tested it but I think you need something like this
<bean id="a" class="com.AClass">
<property name="aProperty" value="y">
<property name="bean2">
<bean class="com.BClass">
<constructor-arg ref="a"/>
</bean>
</property>
</bean>
check here for more help on referencing one bean inside another
The decorator pattern can be expressed in the following way using XML:
<bean id="decorated" class="Outer">
<constructor-arg>
<bean class="Middle">
<constructor-arg>
<bean class="Inner"/>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
This is equivalent to the following Java code:
Common decorated = new Outer(new Middle(new Inner()));
Consider Using #Configuration approach to make this more Java-friendly:
#Bean
public Common outer() {
return new Outer(middle());
}
#Bean
public Common middle() {
return new Middle(inner());
}
#Bean
public Common inner() {
return new Inner();
}