So I have been using the 3.2.0.RELEASE Spring XML configurations for most of my beans but now I am faced with a unique situation where the Getters and Setters can't be used (bad legacy code - can't get around it).
As such, I want to use Spring #Configuration class and the XML to workaround this problem.
However, I am getting "Class Not Found" exception when it tries to read my #Configuration Class.
Caused by: java.lang.ClassNotFoundException: v1.inventory.item.myJavaConfig
My XML file which is failing looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="v1.inventory.item.myJavaConfig"/>
</beans>
My #Configuration class looks like this:
package v1.inventory.item;
#Configuration
#ImportResource("classpath:v1/inventory/item/baseItemConfigs.xml")
public class myJavaConfig {
#Autowired
#Qualifier("parentItem")
Item baseItem;
#Bean
public Item realItem(){
Item modifiedBean = baseItem;
modifiedBean.setManufacturer("Fake Setter for Manufacturer");
modifiedBean.setDesigner("Fake Setter for Designer");
return modifiedBean;
}
}
I need this to be read by the ApplicationContext so I need to make sure these beans can be found. Is this a bug with Spring 3.2.0.RELEASE? Or my code?
For the record, I am pulling in the #Configuration last (parentItem is scanned first in XML).
I figured out the issue here.
It seems that maven/spring (not sure which) wasn't looking in my "resource" directory for the file. Only my "java" directory. When I moved my file into the "java" directory, Spring found the file just fine.
The tests which were passing in JUnit now pass using the Maven compiler (which was throwing the above error during the test phase)
Related
I am very new to Spring Framework. I am using NetBeans for IDE. I followed couple of tutorials to learn it by myself. However, I am stuck in the middle and cannot proceed further. Let me breakdown my project here:
My project folder structure looks like this:
There are two classes; the major one MainApp.java contains following code:
package com.myprojects.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context;
context = new ClassPathXmlApplicationContext("classpath*:beans.xml");
FirstPage obj;
obj = (FirstPage) context.getBean("firstPage");
obj.getMessage();
}
}
Second class file FirstPage.java looks like this:
package com.myprojects.spring;
public class FirstPage {
private String message;
public void setMessage(String message){
this.message = message;
}
public void getMessage(){
System.out.println("Your Message : " + message);
}
}
The beans.xml file looks like below:
<?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-4.0.0.RELEASE.xsd
">
<bean id = "firstPage" class = "com.myprojects.spring.FirstPage">
<property name = "message" value = "Hello World!"/>
</bean>
</beans>
Now, the error I am getting is like below:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'firstPage' is defined
I know I have been doing some silly mistake here.
Thank you in Advance !
Almost similar problem have been discussed before. I think your program is unable to locate beans.xml.
Try doing this:
context = new ClassPathXmlApplicationContext("META-INF/beans.xml");
EDIT:
This new error XmlBeanDefinitionStoreException means that your schema is not valid. Try changing your schema as described in one of these answers:
https://stackoverflow.com/a/21525719/2815219
https://stackoverflow.com/a/25782515/2815219
Spring configuration XML schema: with or without version?
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id = "firstPage" class = "com.myprojects.spring.FirstPage">
<property name = "message" value = "Hello World!"/>
</bean>
</beans>
According to the directory structure you posted it is very likely that src/main/resources is on your classpath. If you like to reference your spring context file beans.xml you have to specify it relative to the folders on your classpath. Hence you should try:
context = new ClassPathXmlApplicationContext("classpath:/META-INF/beans.xml");
Besides: the notation classpath*:beans.xml means you want to read in all context files having a name of beans.xml.
Put beans.xml to outside Meta-inf ,
or use new ClassPathXmlApplicationContext("META-INF/beans.xml");
And http://www.springframework.org/schema/beans/spring-beans-4.0.0.RELEASE.xsd
should change to
http://www.springframework.org/schema/beans/spring-beans-4.0.0.xsd , as spring's xsd filenames don't contain "RELEASE".
The xsd files are in org.springframework.beans.factory.xml package in spring-beans.jar, see if the xsd file is in that package.
Doing following two things solved my issue.
1) There was an incorrect beans.xml path. I changed that to context = new ClassPathXmlApplicationContext("META-INF/beans.xml");.
2) Also, there was an invalid xsi:schemaLocation attribute value. I changed that attribute's value to http://www.springframework.org/schema/beans/spring-beans-3.0.xsd.
Thank you all for your help.
I'm learning spring dependency injection with Struts2, beased on a web project. In my example, I created a zoo having animals. Animal will talk if injection is succeed. E.g. in the console, we will see dog's talk :
Wowowo ฅ^•ﻌ•^ฅ
However, if injection failed, then we'll see :
zooService bean has not been injected.
Here's the architecture of my application :
com.zoo.controller.ZooController is the controller for receiving web actions.
com.zoo.service.ZooService is the interface for animal's talk
com.zoo.service.ZooServiceForDog is the implementation for dog's talk
Problem
Up to the step, everything is OK. And the dependency injection is handled by Spring using an XML file called applicationContext.xml. However, I've 2 types of configuration for this file, the first one Config 1 works but the second Config 2 doesn't.
Injection succeed using config 1.
<?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="zooService" class="com.zoo.service.ZooServiceForDog" />
</beans>
Injection failed using config 2.
<?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="zooController" class="com.zoo.controller.ZooController">
<property name="zooService" ref="zooServiceBean" />
</bean>
<bean id="zooServiceBean" class="com.zoo.service.ZooServiceForDog" />
</beans>
Can somebody explain why the Config 2 cannot work ?
Here're other codes that might be helpful to the issue :
Class com.zoo.controller.ZooController:
package com.zoo.controller;
import com.zoo.service.ZooService;
import com.opensymphony.xwork2.ActionSupport;
public class ZooController extends ActionSupport {
private static final long serialVersionUID = 1L;
private ZooService zooService;
public String live () {
if (zooService != null) {
zooService.talk();
} else {
System.out.println("zooService bean has not been injected.");
}
return SUCCESS;
}
public ZooService getZooService() {
return zooService;
}
public void setZooService(ZooService zooService) {
this.zooService = zooService;
}
}
It cannot work because the scope of the zooController is singleton. You should make the scope prototype.
<bean id="zooController" class="com.zoo.controller.ZooController" scope="prototype" >
<property name="zooService" ref="zooServiceBean" />
</bean>
The dependency management is defined by the container:
If your actions managed by Struts container, then Struts is creating them in the default scope. If your actions is managed by Spring container then you need to define the scope of the action beans, because Spring by default uses singleton scope and if you don't want to share your action beans between user's requests you should define the corresponding scope. You can use prototype scope, which means a new instance is returned by the Spring each time Struts is being built an action instance.
The Struts integrates to Spring via plugin. Make sure it has
<constant name="struts.objectFactory" value="spring" />
then you can delegate actions to Spring
References:
Struts2 and Spring
Spring plugin
EDIT:
In your first config you declared a bean zooService that will be injected by Struts using spring object factory.
In your second config you declared two beans zooController and zooServiceBean, but you changed the name of the second bean. Then you tried to build the action bean using spring object factory like in the first case. And because there's no bean with name zooService the autowiring has been failed. Because by default Struts is configured to autowire beans from the application context by name.
Then you changed struts.xml and used a bean reference in the action class attribute. It means that Struts will use app context to get a bean from Spring. And because it has an explicit dependency on the second bean, it would be wired before the bean is returned.
I'm fairly new to spring so excuse me if this is a dumb question. When I try to launch a program I get the following error: java.lang.IllegalArgumentException: Could not resolve placeholder 'appclient' in string value [${appclient}]. The error is thrown when the following code is executed:
package ca.virology.lib2.common.config.spring.properties;
import ca.virology.lib2.config.spring.PropertiesConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
#Configuration
#Import({PropertiesConfig.class})
#PropertySource("${appclient}")
public class AppClientProperties {
private static final Logger log = LoggerFactory.getLogger(AppClientProperties.class);
{
//this initializer block will execute when an instance of this class is created by Spring
log.info("Loading AppClientProperties");
}
#Value("${appclient.port:}")
private int appClientPort;
#Value("${appclient.host:}")
private String appClientHost;
public int getAppClientPort() {
return appClientPort;
}
public String getAppClientHost() {
return appClientHost;
}
}
A property file called appclient.properties exists in the resources folder with the information for host and port. I'm not sure where the "${appclient}" is defined, if it is at all. Maybe it is not even defined and that is causing the problem. Do I need to change the "${appclient}" to something like "{classpath:/appclient.properties}" or am I missing something else?
You are not reading the properties file correctly. The propertySource should pass the parameter as: file:appclient.properties or classpath:appclient.properties. Change the annotation to:
#PropertySource(value={"classpath:appclient.properties"})
However I don't know what your PropertiesConfig file contains, as you're importing that also. Ideally the #PropertySource annotation should have been kept there.
If you are using Spring 3.1 and above, you can use something like...
#Configuration
#PropertySource("classpath:foo.properties")
public class PropertiesWithJavaConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
You can also go by the xml configuration like...
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:property-placeholder location="classpath:foo.properties" />
</beans>
In earlier versions.
Hopefully it will be still helpful, the application.properties (or application.yml) file must be in both the paths:
src/main/resource/config
src/test/resource/config
containing the same property you are referring
If your config file is in a different path than classpath, you can add the configuration file path as a system property:
java -Dapp.config.path=path_to_config_file -jar your.jar
I know It is an old message , but i want to add my case.
If you use more than one profile(dev,test,prod...), check your execute profile.
In my case , I forgot to add the new property in my application.properties under test folder.Adding it resolved the issue
For properties that need to be managed outside of the WAR:
<context:property-placeholder location="file:///C:/application.yml"/>
For example if inside application.yml are name and id
Then you can create bean in runtime inside xml spring
<bean id="id1" class="my.class.Item">
<property name="name" value="${name}"/>
<property name="id" value="${id}"/>
</bean>
in my case, the war file generated didn't pick up the properties file so had to clean install again in IntelliJ editor.
If the issue occurs in IntelliJ, all you have to do is to install the plugin https://plugins.jetbrains.com/plugin/7861-envfile and follow the steps given.
My solution was to add a space between the $ and the {.
For example:
#Value("${appclient.port:}")
becomes
#Value("$ {appclient.port:}")
I'm using Fuse IDE (Eclipse) on a little project with a spring camel context, one route, and one test. I put an extra xml for defining test execution environment.
When I run the test, it fails with type mismatch loading the context bean info (when instantiating PropertyDescriptor class of the bean context, setter type is org.apache.camel.spring.SpringCamelContext and getter type is org.apache.camel.model.ModelCamelContext...
The original exception is: "java.beans.IntrospectionException: type mismatch between read and write methods"
The test code is this:
public class TestDBRoute extends CamelSpringTestSupport {
#DirtiesContext //reload context
#Test
public void testPoll() throws Exception {
//context.start();
System.out.println("comenzo");
Thread.sleep(1000);
System.out.println("termino");
//context.stop();
assertEquals("first", 1, 1);
}
#Override
protected AbstractApplicationContext createApplicationContext() {
return new ClassPathXmlApplicationContext("classpath:/com/test-camel-context.xml");
}
}
The camel context code is:
<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
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<camelContext xmlns="http://camel.apache.org/schema/spring">
<packageScan>
<package>com.test.fuse.routes</package>
</packageScan>
</camelContext>
</beans>
The route code is empty, it only extends the RouteBuilder and overrides the configure method.
I'm using OpenJDK 1.6.0_24 on ubuntu.
If you need something else please ask.
Thanks
I just clean the workspace and changed my spring version from 2.5.4 to 2.5.6 on the pom.xml and everything works.
Thanks to Claud Ibsen and Babak Vahdat for their help.
Can you enlighten me on this problem I encountered while experimenting with Spring.
I have 2 context here. let's name them springA.xml and springB.xml
springA.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.xsd">
<import resource="springB.xml" />
<bean name="name2" class="java.lang.String"/>
</beans>
springB.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.xsd">
<bean name="name2,name3" class="java.lang.String"/>
</beans>
springC.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.xsd">
<bean name="name3,name2" class="java.lang.String"/>
</beans>
And this is my Java File.
public static void main(String[] args) {
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("springA.xml"));
Object obj1 = factory.getBean("name2");
Object obj2 = factory.getBean("name3");
System.out.println(obj1.getClass().getName() + " " + obj2.getClass().getName());
}
And the result, I get a "java.lang.String java.lang.String". If I change the position of
the name "name2,name3" to "name3,name2" (springC.xml), I get a "java.lang.Object java.lang.Object".
I am just confused as to why the result is like that. I was expecting that the function will return java.lang.String for name2 and java.lang.Object for name3 (since name2 is already used in the springA.xml, I am assuming this name will not be used and instead, will use name3 for springB.xml)
Thanks!
PS:
Spring 2.5
Eclipse 3.5
From Spring's documentation:
Every bean has one or more ids (also
called identifiers, or names; these
terms refer to the same thing). These
ids must be unique within the
BeanFactory or ApplicationContext the
bean is hosted in.
According to this, your combined application context is invalid as it contains two different beans which have the same ID - your bean named "name2" from ContextA.xml and your bean named "name2", aliased "name3" in ContextC.xml. I would expect Spring to issue at least a warning about this.
To answer your question: You shouldn't expect any sane results from this kind of setup. Bean names have to be unique and if they aren't the results are undefined. And by "undefined" I mean "unlikely to be helpful" :)
Hope this helps.
I believe you are seeing different results because Spring is loading the beans in the context in different orders in each scenario. Spring makes no guarantee as to which order it will load it's beans other than the fact that any beans used as "ref"'s in other bean definitions will be loaded before the beans that depend on them.
The correct solution to your problem is DO NOT use duplicate bean identifiers and then you won't have to guess as to which bean you will get when you look one up.
I've ran your code on Spring 2.5.6 and 3.0.0.M1 and both version produce the same result.
java.lang.String java.lang.String
My advice is if you want two strings and you are getting strange results with 2.5, then bump to 2.5.6 or 3.0.0.M1.