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.
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'm a newbie to spring and wonder how java based configs can be converted to xml based bean configs. I know that annotation based configs are more used now a days. But my requirement is to use xml based configs.
Bean configuration is added below.
#Bean
DataStoreWriter<String> dataStoreWriter(org.apache.hadoop.conf.Configuration hadoopConfiguration) {
TextFileWriter writer = new TextFileWriter(hadoopConfiguration, new Path(basePath), null);
return writer;
You can create bean directly in xml configuration
<bean id="dataStoreWriter" class="TextFileWriter">
<constructor-arg index="0" ref="hadoopConfigBean"/>
<constructor-arg index="1">
<bean class="Path">
<constructor-arg index="0" value="/tmp"/>
</bean>
</constructor-arg>
</bean>
If you need non-trivial bean configuration then you can use factory method call in xml configuration
<bean id="dataStoreWriter" class="DataStoreFactory" factory-method="dataStoreWriter">
<constructor-arg index="0" ref="hadoopConfigBean"/>
<constructor-arg index="1" value="/tmp"/>
</bean>
Factory class should look like
public class DataStoreFactory {
public static DataStoreWriter<String> dataStoreWriter(Configuration hadoopConfiguration, String basePath) {
// do something here
TextFileWriter writer = new TextFileWriter(hadoopConfiguration, new Path(basePath), null);
return writer;
}
}
From spring doc
#Bean is a method-level annotation and a direct analog of the XML element. The annotation supports most of the attributes offered by , such as: init-method, destroy-method, autowiring, lazy-init, dependency-check, depends-on and scope.
When you annotate method #bean spring container will execute that method and register the return value as a bean within a BeanFactory. By default, the bean name will be the same as the method name.
#Configuration
public class AppConfig {
#Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
Note :Use #bean along with #configuration
I am new to Spring and I have the following problem:
I have the following bean:
<bean id="lastName" class="java.lang.String">
<constructor-arg value="Johnson"/>
</bean>
Then, in my class RegisterPerson, I have the following
#Configurable
public class RegisterPerson
#Resource(name="lastName")
private String lastName;
then in my method displayName(){
System.out.println(lastName)
}
lastName is null.
I looked for some examples, but couldn't find anything similar to my problem. Any advice or suggestions will be appreciated.
Thanks!
The best way to inject String into your class is declare properties configurer in your Spring XML: something like this:
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true"/>
<property name="locations">
<list>
<value>classpath:/cfg/yourPropsFile.properties</value>
</list>
</property>
</bean>
If you are using annotations make sure that you have these lines in your spring file:
<context:annotation-config/>
<context:component-scan base-package="com.your.app"/>
Then just add that string you want to be injected in your spring bean into that file, for e.g.:
my.prop=Johnson
Then inject it in your controller using #Value annotation:
#Value("${my.prop}")
private String lastName;
This is assuming that your value needs to be configurable.
Otherwise if you need to inject String value as you are trying to do now, please note that by default using #Configurable annotation autowiring won't work. To enable autowiring you need to enable it using: #Configurable(autowire = Autowire.BY_NAME), but it shouldn't be used unless you really need it. #Configurable annotation is mostly used with AspecJ, which is not what you are trying to achieve here.
So define your class with #Component and using:
#Autowired
#Qualifier("lastName")
private String lastName;
will solve your problem.
You should use Autowired and Qualifier annotation..
#Autowired
#Qualifier("lastName")
private String lastName;
Try this configuration
public class Test {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("app-context.xml");
String s = (String) context.getBean("lastName");
}
}
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.
i am using following config in my spring context.xml to register patterns for Java melody configuration.
i want to move this out as a spring bean. can anyone help me with this? i am having trouble setting it up properly.
<bean id="facadeMonitoringAdvisor" class="net.bull.javamelody.MonitoringSpringAdvisor">
<property name="pointcut">
<bean class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="patterns" value="com.abc.service.*.*(..)" />
<property name="excludedPatterns" value="com.abc.service.*.getEntityManager(),com.abc.service.xyz.integration.gateway.*,com.abc.service.xyz.webservice.*" />
</bean>
</property>
</bean>
You should create a #Configuration class. For each bean tag in xml, create a method annotated with #Bean. In this case it would look something like this:
#Configuration
public class MonitoringContext
{
#Bean(name="facadeMonitoringAdvisor")
public MonitoringSpringAdvisor getMonitoringSpringAdvisor() {
MonitoringSpringAdvisor msa = new MonitoringSpringAdvisor();
msa.setPointcut(getJdkRegexpMethodPointcut());
return msa;
}
#Bean
public JdkRegexpMethodPointcut getJdkRegexpMethodPointcut() {
JdkRegexpMethodPointcut jrm = new JdkRegexpMethodPointcut();
jrm.setPatterns("com.abc.service.*.*(..)");
jrm.setExcludedPatterns("com.abc.service.*.getEntityManager(),com.abc.service.xyz.integration.gateway.*,com.abc.service.xyz.webservice.*");
return jrm;
}
}
Check out the Spring documentation for AOP here