I have requirement to dynamically create bean, I want to do something like below
context1 in external filesystem
<bean id="env" class="java.lang.String">
<constructor-arg value="dev"/>
</bean>
<import resource="classpath:context2/>"
context2 in classpath as below :
<bean id="#{env}_config" value="some value here"/>
in java when I try to refer to bean dev_config through context1 application context, it gives exception that dev_config bean not found. How can I achieve this?
you need to add context namespace (must have spring-context.jar) , and specify scan attribute and specify the package you want to scan for new beans
<context:component-scan base-package="{quulified name for your package}">
</context:component-scan>
Each class you want to generate a bean for need to be annotated with #Component
#Component
public class MyClass
Related
I have an application using a framework that provides certain Spring beans via XML files in the framework. The configuration of my application is currently done partly in XML but mostly with Spring annotations.
Some of the XML bean definitions have parents referring to beans supplied by the framework, e.g.
<bean id="MyBean" parent="FrameworkBean">
<property name="context">
<map merge="true">
<entry key="SomeKey" value-ref="SomeValue" />
</map>
</property>
</bean>
FramwworkBean is defined in an XML file in the framework. There is a chain of bean inheritance. At each step some entries are added to the context:
<bean id="FrameworkBean" parent="AbstractBean">
<map merge="true">...
<bean id="AbstractBean" abstract="true" class="ClassWithContext"/>
I understand the result of all this is construction of a ClassWithContext
instance with a map containing all the entries up the chain.
Is it possible to write Java code to do the same, without duplicating code from the framework XML files?
#Bean("MyBean") ClassWithContext myBean() {
return ??? // code that uses "FrameworkBean" somehow
}
The XML bean definition has no dependency on the type of AbstractBean.
If MyBean can be created by Java code, can that code be written to be equally type-agnostic? Or should I just leave this in XML?
If your "FrameworkBean" is not abstract bean you can try the following:
#Bean
public SomeType myBean(#Qualifier("FrameworkBean") FrameworkBeanType frameworkBean) {
SomeType type = getSomeType();
type.setFrameworkBean(frameworkBean);
return type;
}
I have a bean I am trying to configure in Spring context using Constructor injection. When I pass subclass for one of the constructor arguments, the bean is instantiated by Spring container only if I do not specify the "type" attribute. Would anybody have any idea what's wrong? Below are more specifics.
class MyClass{
public MyClass(SomeAbstractBase absObject){
//do stuff
}
}
class ConcreteClass extends SomeAbstractBase{
//
}
Spring configs (First and second do not work but the third one using type attribute works)-
Config I-
<bean id="concreteclass"
class="ConcreteClass"/>
<bean id="myclass"
class="MyClass">
<constructor-arg type="ConcreteClass" ref="concreteclass"/>
</bean>
Config II-
<bean id="concreteclass"
class="ConcreteClass"/>
<bean id="myclass"
class="MyClass">
<constructor-arg type="SomeAbstractBase" ref="concreteclass"/>
</bean>
Config III-
<bean id="concreteclass"
class="ConcreteClass"/>
<bean id="myclass"
class="MyClass">
<constructor-arg ref="concreteclass"/>
</bean>
I get the following exception at initialization-
Exception in thread "main"
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'jedispool' defined in class path resource
[cache-spring-config.xml]: Could not resolve matching constructor
(hint: specify index/type/name arguments for simple parameters to
avoid type ambiguities)
Why would neither of the first or second config work?
Thank you
Type argument accept only the full qualified type (because if not spring cannot determine exactly the package and the type will not match your class):
So you need to use the canonical name of your class to be a type
ConcreteClass => com.your.app.ConcreteClass
A class is not just a name, is a package + name (too be short)
I believe the error you had appeared because you had static nested classes. Here's an SSCCE
package test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(MyClass.class.getName());
System.out.println(ConcreteClass.class.getName());
System.out.println(SomeAbstractBase.class.getName());
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
}
static class MyClass {
public MyClass(SomeAbstractBase absObject) {
}
}
static class ConcreteClass extends SomeAbstractBase {
//
}
static abstract class SomeAbstractBase {
}
}
With spring.xml containing
<bean id="concreteclass" class="test.Test.ConcreteClass" />
<bean id="myclass" class="test.Test.MyClass">
<constructor-arg type="test.Test.SomeAbstractBase" ref="concreteclass" />
</bean>
The above fails with a UnsatisfiedDependencyException. In this specific example, the class attribute isn't used correctly. The fully qualified class name for ConcreteClass is test.Test$ConcreteClass, not test.Test.ConcreteClass as I've specified. The same applies to MyClass and SomeAbstractBase.
However, specifying test.Test.ConcreteClass in the class attribute for the concreteclass bean doesn't fail because at some point during processing of bean declarations, Spring tries to resolve the class String into a Class object using Class.forName(String). It will call ClassUtils.forName(String, ClassLoader) to do this. Initially it will fail because there is no such class test.Test.ConcreteClass. However, this is done in a try-catch which on ClassNotFoundException will transform the String class name from test.Test.ConcreteClass to test.Test$ConcreteClass and try again. It will work and correctly create a bean of type test.Test$ConcreteClass for your concreteclass bean.
When it tries to create your myclass bean, however, it does not apply such logic for resolving which constructor to use and therefore cannot understand that with the type attribute value of test.Test.SomeAbstractBase, you actually meant test.Test$SomeAbstractBase, so it fails saying the type is ambiguous.
Change your bean declarations to correct types
<bean id="concreteclass" class="test.Test$ConcreteClass" />
<bean id="myclass" class="test.Test$MyClass">
<constructor-arg type="test.Test$SomeAbstractBase" ref="concreteclass" />
</bean>
and it will work.
Take a look at kakawait's answer, you need to specify the fully qualified class name for the bean you are trying to instantiate.
I am new to spring and i have a question on autowiring the bean
So basically in my context file i have defined a bean called
<bean id="offerpricedao" class="com.impl.OfferPriceDAOImpl" >
<constructor-arg index="0" ref="offerpriceclass"></constructor-arg>
<constructor-arg index="1" ref="myrole"></constructor-arg>
<constructor-arg index="2"><null/></constructor-arg>
</bean>
And every other bean i have defined here which are referring ..
This code is in src main java..
and in src main test i have a testng test which loads this configuration file and in my test
i have some thing like this
#ContextConfiguration(locations = { "classpath:Context.xml" })
public class SetOfferPricesTest extends AbstractTestNGSpringContextTests {
#Autowired
IOfferPriceDAO test;
}
and this autowiring works fine ...
I thought we should have this in my configuration file for autowire work..
with out this how my autowiring is working..?
You might be having something like default-autowire="byName" in context xml. When you add #Autowired Spring finds the implementation of that interface and autowires it. In your case the implementation is com.impl.OfferPriceDAOImpl
Also the #ContextConfiguration annotation loads the context xml from the classpath
Above config and code is not enough to say how it works.
Since it Works,so the bean is defined some where in the Context.xml or in the xml files imported in context.xml.
And what dhanush said is also true.
I have a resource file created in my project. I want to inject values from resource file into spring bean. i defined the place holder for resource file in the applicacationContext.xml.
<context:property-placeholder location="file:///${MRAPOR_PROPPATH}mRapor.properties" />
I can inject values to beans which is declared in the applicationContext.xml like :
<bean
id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean" >
<property
name="jndiName"
value="${database.jndiName}" />
<property
name="lookupOnStartup"
value="false" />
<property
name="cache"
value="true" />
<property
name="proxyInterface"
value="javax.sql.DataSource" />
</bean>
This works well. However, i can not inject values if i declare beans with spring annotations.
#Component("SecurityFilter")
public class SecurityFilter implements Filter {
public static final String USER = "USER_SESSION_KEY";
public static final String CENTRIFY_USERNAME_KEY = "REMOTE_USERNAME";
#Value("${url.logout}")//I get error here !!!!
private String logoutUrl;
//proper setters and getters.
}
Do you have any idea why i can not access values inside the beans declared using annotations.
Here is my exception
weblogic.application.ModuleException:
at weblogic.servlet.internal.WebAppModule.startContexts(WebAppModule.java:1510)
at weblogic.servlet.internal.WebAppModule.start(WebAppModule.java:482)
at weblogic.application.internal.flow.ModuleStateDriver$3.next(ModuleStateDriver.java:425)
at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:52)
at weblogic.application.internal.flow.ModuleStateDriver.start(ModuleStateDriver.java:119)
Truncated. see log file for complete stacktrace
Caused By: java.lang.IllegalArgumentException: Could not resolve placeholder 'url.logout' in string value [${url.logout}]
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:173)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:125)
at org.springframework.beans.factory.config.PropertyPlaceholderConfigurer$PlaceholderResolvingStringValueResolver.resolveStringValue(PropertyPlaceholderConfigurer.java:255)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:748)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:745)
Are you sure that the instance of SecurityFilter that actually filters requests is managed by Spring?
By default Filters declared in web.xml are instantiated by servlet container, therefore they are not managed by Spring and Spring annotations such as #Value won't work in them.
However, Spring provides special support for your use case - you can delegate filtering to a component managed by Spring using DelegatingFilterProxy. Declare it in web.xml as follows:
<filter>
<filter-name>SecurityFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>...</filter-mapping>
DelegatingFilterProxy will delegate request filtering to a bean named SecurityFilter (as in your #Component).
The #Value is processed by the java compiler whereas the the XML is parsed by Spring Bean Processor - these are two very different things... Why do you assume that should work in the same manner?
Edit: I read up on it and it seems to actually be possible using the Spring EL, you only have to prefix with # instead of $:
private #Value( "#{application.url.logout}" ) String logoutUrl;
Cheers,
I have a bean definition like this:
<bean id="myService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceInterface" value="org.myapp.MyService"/>
<property name="serviceUrl" value="rmi://localhost:1099/myService"/>
</bean>
I retrieve the service bean in this way:
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:rmi-client-config.xml");
MyService myService = context.getBean("myService", MyService.class);
Of course it returns an Instance of "MyService" impl and not RmiProxyFactoryBean.
So how can I change "serviceUrl" parameter using the xml definition above and not manually instancing RmiProxyFactoryBean?
To get the FactoryBean instance instead of the bean created by the factory, use the BeanFactory.FACTORY_BEAN_PREFIX. ie
RmiProxyFactoryBean rpfb = (RmiProxyFactoryBean) contex.getBean("&myService");