I've a class which takes in 2 Object Injections. 1 of them is to be injected through other bean ref whereas the other injected based on bean call. I want to instantiate an object using spring. How can I do this ?
I tried doing this:
MyBean Class:
class MyBean{
Injection1 ijn1;
MyBean(Injection1 ijn1,Injection2 ijn2){
this.ijn1=ijn1;
this.ijn2=ijn2;
}
}
Beans.xml
<bean name="myBean" class="MyBean" scope="prototype">
<constructor-arg>
<null />
</constructor-arg>
<constructor-arg>
<ref bean="injection2" />
</constructor-arg>
</bean>
<bean name="injection2" class="Injection2">
</bean>
Application Code:
MyBean getMyBean(Injection ijn1) {
return (MyBean)context.getBean("myBean", new Object[] { ijn1 })
}
But this doesn't works.
Any tips ?
You code doesn't work because spring looks for a MyBean's constructor like MyBean(Injection1 ijn1); you have to pass injection2 in this way.
MyBean getMyBean(Injection ijn1) {
return (MyBean)context.getBean("myBean", new Object[] { ijn1, context.getBean("injection2") })
}
If you want to use your code another way is to have partial inject in this way:
class MyBean{
Injection1 ijn1;
Injection2 ijn2;
MyBean(Injection1 ijn1){
this.ijn1=ijn1;
}
public void setIjn2(Injection2 ijn2I ) {
this.ijn2 = ijn2;
}
}
and in xml
<bean name="myBean" class="MyBean" scope="prototype">
<property name="inj2" ref="injection2" />
</bean>
<bean name="injection2" class="Injection2">
</bean>
Related
I've got two PropertyPlaceHolderConfigurer in my Spring XML. The first one obtains application properties from a file. The second one obtains user properties from database and looks like this:
<myConfiguration>
<bean id="databaseProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="properties">
<bean class="org.apache.commons.configuration.ConfigurationConverter"
factory-method="getProperties">
<constructor-arg>
<ref bean="propertiesSource" />
</constructor-arg>
</bean>
</property>
</bean>
<bean id="propertiesSource" class="org.apache.commons.configuration.DatabaseConfiguration">
<constructor-arg type="javax.sql.DataSource" ref="tomcatDataSource" />
<constructor-arg value="application_properties" />
<constructor-arg value="PROPERTY_KEY" />
<constructor-arg value="PROPERTY_VALUE" />
</bean>
<bean id="propertiesService" class="com.xxx.PropertiesServiceImpl">
<property name="propertiesSource" ref="propertiesSource"></property>
</bean>
<myConfiguration>
It works properly and I can access to these properties injecting 'propertiesService' like:
#Autowired
private PropertiesService propertiesService;
Which is:
public class PropertiesServiceImpl implements PropertiesService {
#Autowired
private DatabaseConfiguration propertiesSource;
private Properties properties;
#Override
public String getProperty(String key) {
if (properties == null) {
properties = ConfigurationConverter.getProperties(propertiesSource);
}
return properties.getProperty(key);
}
#Override
public Properties getProperties() {
if (properties == null) {
properties = ConfigurationConverter.getProperties(propertiesSource);
}
return properties;
}
The problem is that I like to use #Value annotation but it does not work.
I've tried:
private #Value("#{propertiesService.helloWorld}") String helloWorld;
And, of course, the property exists and is reachable through 'propertiesService' but it results in the next error:
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 18): Property or field 'helloWorld' cannot be found on object of type 'com.infraportal.model.properties.PropertiesServiceImpl' - maybe not public?
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:224)
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:94)
at org.springframework.expression.spel.ast.PropertyOrFieldReference.access$000(PropertyOrFieldReference.java:46)
at org.springframework.expression.spel.ast.PropertyOrFieldReference$AccessorLValue.getValue(PropertyOrFieldReference.java:374)
at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:88)
at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:120)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:242)
at org.springframework.context.expression.StandardBeanExpressionResolver.evaluate(StandardBeanExpressionResolver.java:161)
Which makes me think that Spring is looking for a 'getHelloWorld()' method instead using 'getProperty(String key)'
Any suggestion?
You need to explicitly specify which method is to be invoked, on bean referred in EL, and supply the argument value as below
#Value("#{propertiesService.getProperty('helloWorld')}")
private String helloWorld;
#Value: It is used for expression-driven dependency injection.
If you want to use with below example.
sample code
#Configuration
#PropertySource("classpath:jdbc.properties")
public class AppConfig {
#Value("${jdbc.driverClassName}")
private String driverClassName;
#Value("${jdbc.url}")
private String jdbcURL;
#Value("${jdbc.username}")
private String username;
#Value("${jdbc.password}")
private String password;
.....
..
}
I'm trying to move from a xml based config to java annotations
I need your help getting this to work:
Obviously I can't set the RemoteJco interface to my SapConnector but what can I do to get this xml-config working?
#Bean
public RmiProxyFactoryBean jcoPool(){
RmiProxyFactoryBean jcoPool = new RmiProxyFactoryBean();
jcoPool.setServiceUrl("rmi://localhost/CH");
jcoPool.setServiceInterface(RemoteJco.class);
jcoPool.setRefreshStubOnConnectFailure(true);
return jcoPool;
}
#Bean
public SapConnector SapConnector(){
SapConnector sapConnector = new SapConnector();
sapConnector.setJcoPool(jcoPool());
return sapConnector;
}
this in the XML-Config works just fine:
<!-- JCO-Pool RMI Service -->
<bean id="jcoPool" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://localhost/CH"/>
<property name="serviceInterface" value="com.itensis.jco.common.RemoteJco"/>
<property name="refreshStubOnConnectFailure" value="true" />
</bean>
<bean id="SapConnector" class="com.itensis.core.SapConnector">
<property name="jcoPool">
<ref bean="jcoPool" />
</property>
</bean>
this is my SAP-Connector
#Service
public class SapConnector {
#Autowired private RemoteJco jcoPool;
public RemoteJco getJcoPool() {
return jcoPool;
}
public void setJcoPool(RemoteJco jcoPool) {
this.jcoPool = jcoPool;
}
}
You have to make some changes on the jcoPool bean:
#Bean
public RemoteJco jcoPool(){
RmiProxyFactoryBean jcoPool = new RmiProxyFactoryBean();
jcoPool.setServiceUrl("rmi://localhost/CH");
jcoPool.setServiceInterface(RemoteJco.class);
jcoPool.setRefreshStubOnConnectFailure(true);
jcoPool.afterPropertiesSet();
return (RemoteJco) jcoPool.getObject();
}
Make sure that you return value has the same class as you used as service interface. And you have to call afterPropertiesSet() before calling getObject on the RmiProxyFacotoryBean instance.
Is it possible to invoke static method in Spring configuration file?
public MyClass {
public static void staticMethod() {
//do something
}
}
<bean id="myBean" class="MyClass">
<!-- invoke here -->
</bean>
When the static method creates an instance of MyClass you an do it like this
config
<bean id="myBean" class="MyClass" factory-method="staticMethod">
<!-- invoke here -->
</bean>
code
public static MyClass staticMethod() {
//create and Configure a new Instance
}
If you want the method only to be called on bean instantiation spring can't do it this way.
config
<bean id="myBean" class="MyClass" init-method="init">
<!-- invoke here -->
</bean>
code
public static void staticMethod() {
//create and Configure a new Instance
}
public void init() {
staticMethod();
}
try this
<bean id="b1" class="org.springframework.beans.factory.config.MethodInvokingBean">
<property name="staticMethod" value="MyClass.staticMethod" />
</bean>
see http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/config/MethodInvokingBean.html
Try something like this:
<!-- call static method -->
<bean id="test" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="MyClass" />
<property name="targetMethod" value="staticMethod" />
<property name="arguments">
<list>
<value>anArgument</value>
</list>
</property>
</bean>
Remove arguments as you might not need them.
Taken from https://gist.github.com/bulain/1139874
I was needing to call a static method. The above code worked fine.
This might be useful as well: How to make spring inject value into a static field.
If you are using annotations for spring configuration you can add the following method into your #Configuration class:
#Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setStaticMethod("MyClass.staticMethod");
return methodInvokingFactoryBean;
}
Which is the properly way to translate this bean:
<bean id="artifactBinding" class="org.springframework.security.saml.processor.HTTPArtifactBinding">
<constructor-arg ref="parserPool"/>
<constructor-arg ref="velocityEngine"/>
<constructor-arg>
<bean class="org.springframework.security.saml.websso.ArtifactResolutionProfileImpl">
<constructor-arg>
<bean class="org.apache.commons.httpclient.HttpClient">
<constructor-arg>
<bean class="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager"/>
</constructor-arg>
</bean>
</constructor-arg>
<property name="processor">
<bean class="org.springframework.security.saml.processor.SAMLProcessorImpl">
<constructor-arg ref="soapBinding"/>
</bean>
</property>
</bean>
</constructor-arg>
</bean>
<bean id="soapBinding" class="org.springframework.security.saml.processor.HTTPSOAP11Binding">
<constructor-arg ref="parserPool"/>
</bean>
from XML to Java-Config?
You can also narrow the scope of the required collaborator object by forming
#Bean
public HTTPArtifactBinding artifactBinding(ParserPool parserPool, VelocityEngine velocityEngine) {
return new HTTPArtifactBinding(parserPool, velocityEngine, artifactResolutionProfile());
}
If Spring can resolve the parserPool and velocityEngine, then it can inject into your #Bean def method.
#Configuration
public class Configuration {
#Autowired
private ParserPool parserPool;
#Autowired
private VelocityEngine velocityEngine;
#Bean
public HTTPArtifactBinding artifactBinding() {
return new HTTPArtifactBinding(parserPool, velocityEngine, artifactResolutionProfile());
}
private ArtifactResolutionProfile artifactResolutionProfile() {
final ArtifactResolutionProfile artifactResolutionProfile = new ArtifactResolutionProfile(new HttpClient(new MultiThreadedHttpConnectionManager()));
artifactResolutionProfile.setProcessor(new SAMLProcessorImpl(soapBinding()));
return artifactResolutionProfile;
}
#Bean
public HTTPSOAP11Binding soapBinding() {
return new HTTPSOAP11Binding(parserPool);
}
}
I have problem when injection class.
In my configuration I have one class which setting level of login and then one variable for setting level:
<bean id="config" class="..." init-method="init">
<property name="log4jConfig" ref="log4j" />
<property name="levelLogging" value="9" />
</bean>
and code:
public void setlevelLogging(Integer level) {
if (level == null) {
set0();
} else {
switch (level) {
case 0:
set0();
break;
case 9:
set9();
}
}
this.level = level;
}
private void set0() {
log4jConfig.setLoggerLevel("org.springframework.ws.server.MessageTracing", "OFF");
log4jConfig.setLoggerLevel("org.app", "INFO");
log4jConfig.setLoggerLevel("org.springframework.ws.client.MessageTracing", "OFF");
}
public void setLog4jConfig(Log4jConfigJmx log4jConfig) {
this.log4jConfig = log4jConfig;
}
when I want to run this code I got NPE because log4jConfig is null when is setlevelLogging calling.
How I can solve this exception ?
now I exclude this class from properties and creating new class in configClass:
Log4jConfigJmx log4jConfig = new Log4jConfigJmx()
but I dont think this is good idea
EDIT:
I try example below but I have still some problem:
first I got this exception:
[ERROR] java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
because I am using transactional and AOP so I add default constructor to the class so I have two of them:
public Config() {
}
public Config(Log4jConfigJmx log4jConfig, Integer level) {
this.log4jConfig = log4jConfig;
setlevelLoggin(level);
}
setlevelLogging ...
<bean id="config" class="..." init-method="init">
<constructor-arg index="0" ref="log4j" />
<constructor-arg index="1" value="9" />
</bean>
but now I have still NPE
pls help
You should place the code from the method setLoggingLevel in the init method.
Only leave this.level = level so it is a plain setter.
The init method is called after all the properties have been set.
----EDIT after comment----
After you comment I suggest you use a constructor:
public Class(Integer level, Log4jConfigJmx log4jConfig){
this.log4jConfig = log4jConfig;
setLevelLogging(level);
}
<bean id="config" class="..." init-method="init">
<constructor-arg index="0" value="9"/>
<constructor-arg index="1" ref="log4j"/>
</bean>
You can use constructor-args like this:
<bean id="config" class="..." init-method="init">
<constructor-arg><ref bean="anotherExampleBean"/></constructor-arg>
<constructor-arg type="int"><value>9</value></constructor-arg>
</bean>
Then your constructor can initialise both variables whilst keeping your setter methods in place.
E.g.
public MyClass(Log4jConfigJmx log4jConfig, Integer level) {
this.log4jConfig = log4jConfig;
this.setLevelLogging(level);
}
You can also try making the log4jConfig autowired.
Change your bean config back to:
<bean id="config" class="..." init-method="init">
<property name="levelLogging" value="9" />
</bean>
And then simply annotate a field in your class to be autowired:
#Autowired
private Log4jConfigJmx log4jConfig;
Add this at the top of your spring context to enable annotations:
<context:annotation-config />