I have put most of the class under
com.company.productline.product -- classpath 1
within that class path there will be service, web, domain, i18n... subpackages.
For some reason, there is another service bean I wrapped in a jar, which should work for the whole productline, hence it is under
com.company.productline -- classpath 2
So in applicationContext.xml, the base-package for component-scan have to compromise to one level up, as classpath 2 instead of classpath 1, like this
<context:component-scan base-package="com.company.productline">
<context:exclude-filter expression=".*_Roo_.*" type="regex"/>
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
Then to make Spring to scan #Service or #Component across the whole application even within that jar file.
However, now in applicationContext there is an error saying:
Annotation-specified bean name 'someServiceClass' for bean class
[com.company.productline.i18n.someServiceClass] conflicts with existing,
non-compatible bean definition of same name and class
[com.company.productline.product.i18n.someServiceClass]'
The problem is Spring seems find a bean class under a false package com.company.productline.i18n.someServiceClass without the product in the middle, but here are what I can confirm:
There is not a class/classpath under the package com.company.productline.i18n.someServiceClass, but there is a class under com.company.productline.product.i18n.someServiceClass.
The class someServiceClass does have a #Component annotation.
But if I take one level down of the classpath in base-package, the error is gone:
<context:component-scan base-package="com.company.productline.product">
<context:exclude-filter expression=".*_Roo_.*" type="regex"/>
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
the class is defined like this:
#Component
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, value = "request")
public class SomeServiceClass implements CurrentRequest {
#Autowired
private HttpServletRequest request;
public Locale getCurrentLocale() {
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
return localeResolver.resolveLocale(request);
}
public HttpServletRequest getRequest() {
return request;
}
public void setRequest(HttpServletRequest request) {
this.request = request;
}
}
So really not sure what's going on and why have this problem.
The application is running on Spring 3.1.0 on STS 2.9.1
Please help, thanks in advance.
Turns out ninn is correct. There is no other possibility but only a class with same bean name within the application.
The reason the project search doesn't work out in this case is that we have another jar file with the same service class. I wasn't know that until noticed. After remove the class within the source code then the error is gone.
Thanks ninn.
Related
I am trying to set up a test applicationContext file for running integration tests on a project that I am working on.
I have two classes that have fields that are marked as #Resource. One class I can change and one I cannot as it is imported from a different project that I don't have any permissions to change. I cannot get my configuration file to set these #Resouces fields without giving me an org.springframework.beans.factory.NoUniqueBeanDefinitionException.
Simple example:
appconfig.xml file
...Typical spring setup...
<bean id="baseUrl" class="java.lang.String">
<constructor-arg value="myURL"/>
</bean>
<bean id="supportedLang" class = "java.lang.String">
<constructor-arg value="en"/>
</bean>
Class that uses baseURL, (I have control to change, simplified Version)
#Service("myService")
public class MyService implements AnotherService{
#Resource
private String baseUrl;
public String getBaseUrl(){return baseUrl;}
public void setBaseURL(String baseURL){this.baseUrl = baseUrl;}
}
Class that uses supportedLang (I don't have access to change this class simplified version)
#Service
public class LangSupportImpl implements InitializaingBean, LangSupport{
#Resource(name= "supportedLang")
private String twoLetterSupportedLang;
public getTwoLetterSupportedLang(){return this.twoLetterSupportedLang;}
}
If I don't set up the beans in the application config file I get a no bean defined error instead.
Any help would be greatly appreciated.
Try to use #Resource(name = "baseUrl") in your MyService class. This will tell Spring which exact bean to take and will resolve ambiguity.
Another option is to change XML configuration and add primary="true" to declaration of baseUrl bean
We are using spring's component-scan and don't want application context to load test beans (even if they are defined in the same path i.e a.b.c).
MyPackage
src
a.b.c.SRC
tst
a.b.c.TST
I have read that order would be to load src folder first and then the test folder. In above case, if I component-scan a.b.c, I only want to load beans from SRC. How is that possible?
You can use the #Profile("ProfileName") annotation on your components and of course setting the active profile on execution. The Component Scan will ignore beans that dont match the active profile. e.g.
#Component
#Profile("production")
public class productionImpl implements SomeInterface{}
#Component
#Profile("test")
public class testImpl implements SomeInterface{}
All you have to do after that is setting the correct profile in live execution. You can set it either as a JVM argument (spring.profiles.active) or set it to the applicationContext: ApplicationContext.getEnvironment().setActiveProfiles(“ProfileName”);
For your test execution classes you can use #ActiveProfiles("TestProfileName")
You can check this site for a more detailed example: http://websystique.com/spring/spring-profile-example/
There are several exclude filters for classpath scanning you can define in your context configuration file. aspectj filter type seems to be the one you would want to use.
<context:component-scan base-package="a.b.c">
<context:exclude-filter type="aspectj" expression="a.b.c.TST.*" />
</context:component-scan>
Alternatively, if you would like to have a bit more granularity, you can define your own annotation and use the annotation exclude-filter type.
<context:component-scan base-package="com.example">
<context:exclude-filter type="annotation" expression="path.to.your.package.ScanExclude"/>
</context:component-scan>
This way, all classes annotated with #ScanExclude annotation are effectively ignored
I'm trying to define error messages in a resource file, but I can't seem to get them to load so I can use them in my controller.
My servlet-context.xml file:
<beans:bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<beans:property name="basename" value="classpath:messages" />
</beans:bean>
My form:
public class LoginForm {
#NotEmpty
private String username;
// getters and setters
}
My messages.properties file (in the root of my source folder, so it gets compiled to the root of my classes folder):
NotEmpty.loginForm.username=test1
NotEmpty.username=test2
NotEmpty.java.lang.String=test3
NotEmpty=test4
My controller:
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(#Valid LoginForm form, BindingResult result) {
if (result.getFieldErrors().size() > 0) {
FieldError firstError = result.getFieldErrors().get(0);
System.out.println(firstError.getDefaultMessage());
}
// ...
}
However, the output of the getDefaultMessage call is never what I define in my resource file! It is always may not be empty (the default).
I've tried a variety of different entries in my context file but it seems like it's not loading the resource file. What am I doing wrong?
According to this documentation, all you need is to put a properties file called ValidationMessages.properties at the root of your project classpath.
You can then add properties with the following format
org.hibernate.validator.constraints.NotEmpty.message=Default message, can not be empty
NotEmpty.ClassName.fieldName=fieldName can not be empty.
where ClassName is the name of your class and fieldName is the name of the field of that class.
You might need to do some configuration to set the correct MessageInterpolator, but I think the default one will do what you need.
First idea:
Try to rename property keys from NotEmpty.loginForm.username to NotEmpty (Just to check if messageSource works correctly). If still not working there is
Second idea:
Where do you perform scanning of components?
Assume that you have two spring configurations: applicationContext.xml (or other name) and servlet-context.xml.
If you have such structure <context:component-scan base-package="by.company.app" /> in applicationContext than your controllers have no defined messageSource - so it cannot load customized messages. It is because #Controller bean is in one spring context, MessageSource bean - in another. (To check this you can simple declare #Autowired MessageSource messageSource field in controller and see in debug is it null or not) In that case you can modify component-scan in applicationContext to:
<context:component-scan base-package="by.company.app">
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
and add following configuration to servlet-context.xml:
<context:component-scan base-package="by" use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
Hope this helps
Unfortunately it looks like a MessageSource must be defined and then used in the appropriate Java class. The getDefaultMessage() method doesn't appear able to read from message properties.
In a component-scanned class:
#Autowired
private MessageSource messageSource;
public String getMessage(FieldError field) {
return messageSource.getMessage(field, null);
}
This will iterate through all possibilities in the message properties files and then--if nothing is found--falls back on the getDefaultMessage() results.
Additionally I updated my servlet-context.xml file to define my messageSource with the basename value of /WEB-INF/classes/messages, as opposed to what I had in my question above.
I spent some time to fix this issue, I done a following changes, now it is working fine in Spring 4.0 MVC and Hibernate 4.1.9
1.put messages under source folder.
If ReloadableResourceBundleMessageSource is not working change to
class="org.springframework.context.support.ResourceBundleMessageSource">
changes property like '<'property name="basename" value="messages"/>
In Message.properties file, the key should be in the following format.
NotEmpty.userForm.userId
userForm-->Model class name.
(If your Model class name is UserForm, then it should
be mentioned as userForm)
userId--> attribute of userForm class
I have the following controller defined:
#Controller
#RequestMapping("/test")
public class MyController extends AbstractController
{
#Autowired
public MyController(#Qualifier("anotherController") AnotherController anotherController))
{
...
}
}
I'm wondering if it's possible to use variables in the #Qualifier annotation, so that I can inject different controllers for different .properties files, e.g.:
#Controller
#RequestMapping("/test")
public class MyController extends AbstractController
{
#Autowired
public MyController(#Qualifier("${awesomeController}") AnotherController anotherController))
{
...
}
}
Whenever I try I get:
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No matching bean of type [com.example.MyController] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this
dependency. Dependency annotations:
{#org.springframework.beans.factory.annotation.Qualifier(value=${awesomeController})
I've included the following bean in my config.xml file:
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:config/application.properties</value>
</list>
</property>
</bean>
But the bean doesn't work unless I declare the bean explicitly in the xml file.
How do I do this with annotations??
First I think it is bad practice to make the dependency injection rely on configuration properties. You are probably going a wrong direction trying to do this.
However to answer your question: accessing placeHolder properties requires the dependency injection to be finished. To make sure it is, you can put your code that accesses the property inside a #PostContruct annotated method.
You will need to retrieve the bean manually from the applicationContext using getBean() method.
#Value("${awesomeController}")
private String myControllerName;
#PostConstruct
public void init(){
AnotherController myController = (AnotherController) appContext.getBean(myControllerName);
}
I'm not sure if what you're doing is possible but I can suggest a slightly different approach, but only if you're using Spring 3.1+. You could try using Spring Profiles.
Define the different controllers you want, one per profile:
<beans>
<!-- Common bean definitions etc... -->
<beans profile="a">
<bean id="anotherController" class="...AnotherController" />
</beans>
<beans profile="b">
<!-- Some other class/config here... -->
<bean id="anotherController" class="...AnotherController"/>
</beans>
</beans>
Your Controller would lose the #Qualifier and become something like:
#Autowired
public MyController(AnotherController anotherController) {
...
}
Then at runtime you can specify which controller bean you want to use by activating the corresponding profile using a system property, e.g.:
-Dspring.profiles.active="a"
or:
-Dspring.profiles.active="b"
It may be possible to set profiles based on a property file but you can find out more about Spring Profiles from this post on the Spring blog. I hope that helps somewhat.
I am having difficulty understanding why something in Spring Java Config using #Autowired does not work.
First, I am trying to move all my #Autowired annotations in the Java Config classes. This has the effect of making my "POJOs" back into real POJOs. I can then not only test them easily outside of a Spring context, but can also use mock objects easily and readily.
So I first tried this:
#Configuration
public class Module3ConfigClass {
#Autowired
private Module1Bean1 module1Bean1;
#Autowired
private Module2Bean1 module2Bean1;
#Bean
public Module3Bean1 module3Bean1() {
return new Module3Bean1(module1Bean1, module2Bean1);
}
}
However, when the Module3Bean1 constructor is invoked, both passed in Beans are null. If you didn't follow my made up naming convention above, both of those beans would be created by a separate Java Config configuration file. Also note that everything is wired up correctly - I know this because everything works perfectly when the #Autowired tags are on the corresponding private member fields inside of Module3Bean1.
FWIW, I tried adding an #DependsOn annotation to module3Bean1() method, but had the same results. I guess I just would really like to understand this behavior, is it correct (I suspect it is, but why)?
Finally, I found an acceptable workaround shown here:
#Configuration
public class Module3ConfigClass {
#Bean
#Autowired
public Module3Bean1 module3Bean1(Module1Bean1 module1Bean1, Module2Bean1 module2Bean1) {
return new Module3Bean1(module1Bean1, module2Bean1);
}
}
This seems fine to me, but if anyone would care to comment on it, that would be welcome as well.
I think you came across same problem I just had. In my case problem was invalid xml configuration. In my module B I had config like :
<beans>
<context:component-scan base-package="com.moduleB"/>
<import resource="classpath:applicationContext-moduleA.xml"/>
</beans>
In moduleA context I placed "context:annotation-config" annotation.
When I change import/context order to :
<beans>
<import resource="classpath:applicationContext-moduleA.xml"/>
<context:component-scan base-package="com.moduleB"/>
</beans>
Autowiring for configuration class properties started to work.
We had the same issue and came to the conclusion that the error arose because we had a circular dependency where a BeanPostProcessor was involved.
A PropertyPlaceholderConfigurer (a BeanPostProcessor) has been configured to set its propertiesArray property with the help of another bean:
<bean id="globalPropertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
lazy-init="false" depends-on="javaLoggingConfigurer">
<property name="locations">
<list>
<value>classpath:config/host/${env.instance}.properties</value>
<value>WEB-INF/config/host/${env.instance}.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="true" />
<property name="propertiesArray" value="#{springPropertyFinder.findProperties()}" />
</bean>
The used springPropertyFinder bean to set the propertiesArray is not a BeanPostProcessor but a "normal" bean that gathers all Properties instances with:
public Properties[] findProperties() {
Map<String, Properties> propertiesMap = applicationContext.getBeansOfType(Properties.class);
for (String title : propertiesMap.keySet()) {
PropertiesLoggerUtil.logPropertiesContent(logger, "Springcontext Properties ("+title+")", propertiesMap.get(title));
}
return propertiesMap.values().toArray(new Properties[propertiesMap.size()]);
}
The #Configuration class contained a bean of type Properties
So our assumption is that the #Configuration class has been created without being processed by the ConfigurationClassPostProcessor (also a BeanPostProcessor), because the PropertyPlaceholderConfigurer depends on the springPropertyFinder, which depends on the properties bean in the #Configuration class. The order of the BeanPostProcessors is probably not setup right under these circumstances.
This described setup worked in XML, but not with Java config.