I have set up my resources like this:
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename">
<value>locale\\messages</value>
</property>
</bean>
My propertyFile:
battle.name=TestBattle
I would like to reach the text "TestBattle" when I use a bean:
<bean id="battlefield" class="com.mypackage.Battlefield" scope="prototype">
<constructor-arg index="0" value="battle.name" />
<constructor-arg index="1" ref="armies" />
</bean>
I want to refeer the message in the propertyFile in this line
<constructor-arg index="0" value="battle.name" />
Is there a way to do it without going into java using the
getMessage("battle.name",...
code in java?
At least, you could use spel to do it.
for example
<bean id="messageSourceAccessor" class="org.springframework.context.support.MessageSourceAccessor">
<constructor-arg ref="messageSource" />
</bean>
<bean id="battlefield" class="com.mypackage.Battlefield" scope="prototype">
<constructor-arg index="0" value="#{messageSourceAccessor.getMessage('battle.name')}" />
<constructor-arg index="1" ref="armies" />
</bean>
However it seems cumbersome if you have to translate many codes.
Other option is using a String to String PropertyEditor to do the translation.
public class MessageSourcePropertyEditor extends PropertyEditorSupport {
private MessageSourceAccessor messageSourceAccessor;
public MessageSourcePropertyEditor(MessageSource messageSource) {
this.messageSourceAccessor = new MessageSourceAccessor(messageSource);
}
#Override
public void setAsText(String text) throws IllegalArgumentException {
String value = text;
if (text.startsWith("i18n:")) {
value = messageSourceAccessor.getMessage(text.substring(5));
}
setValue(value);
}
}
public class MessageEditorRegistrar implements PropertyEditorRegistrar {
private MessageSource messageSource;
#Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(String.class, new MessageSourcePropertyEditor(messageSource));
}
public MessageSource getMessageSource() {
return messageSource;
}
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}
}
And use the prefix i18n: to translate codes, ie
<bean id="propertyEditorConfigure" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="message.MessageEditorRegistrar">
<property name="messageSource" ref="messageSource" />
</bean>
</list>
</property>
</bean>
<bean id="battlefield" class="com.mypackage.Battlefield" scope="prototype">
<constructor-arg index="0" value="i18n:battle.name" />
<constructor-arg index="1" ref="armies" />
</bean>
Related
I try to implement an own PropertyPlaceholderConfigurer which uses properties of an other PropertyPlaceholderConfigurer in the constructor. I tried doing it like this.
<!-- load properties which are used in second configurer -->
<context:property-placeholder
location="classpath:config.properties" ignore-unresolvable="true" order="1" />
<bean class="com.example.MyPropertyPlaceholderConfigurer">
<!-- use property of other file -->
<constructor-arg value="${password}" />
<property name="location">
<value>file:config.properties</value>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true" />
</bean>
config.properties
password=1234
But the property ${password} in the constructor of MyPropertyPlaceholderConfigurer is not resolved.
What is my mistake?
I post hereby my solution I came up with to overcome this problem.
I implemented a single PropertyPlaceholderConfigurer which loads all properties and adds special functionality to some properties. This way inside the PropertyPlaceholderConfigurer you are able to use properties which are defined in the loaded property files.
config.properties
password=1234
special.properties
user={SPECIAL}name
spring config:
<bean
class="com.example.MyPropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="locations">
<list>
<value>classpath:config.properties</value>
<value>classpath:special.properties</value>
</list>
</property>
</bean>
PropertyPlaceholderConfigurer:
public class MyPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
private final static String PROPERTY_PREFIX = "{SPECIAL}";
protected Properties properties;
#Override
protected void convertProperties(Properties props) {
this.properties = props;
super.convertProperties(props);
}
#Override
public String convertPropertyValue(String originalValue) {
if (originalValue.startsWith(PROPERTY_PREFIX)) {
return convert(originalValue.substring(PROPERTY_PREFIX.length()));
}
return originalValue;
}
protected String convert(String value){
// access properties from config.properties
String pw = this.properties.getProperty("password");
// use properties and do what you need to do
return value + pw;
}
}
Maybe it helps somebody.
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'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>
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 />
I need help making AOP work. What am I missing here?
<?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-2.0.xsd">
<bean id="duke" class="com.tutorial.springidol.Singer">
<constructor-arg value="Duke"/>
<constructor-arg>
<bean class="com.tutorial.springidol.Song">
<property name="title" value="ABC"/>
</bean>
</constructor-arg>
</bean>
<bean id="audienceAdvice" class="com.tutorial.advice.AudienceAdvice">
<property name="audience">
<bean class="com.tutorial.springidol.Audience"/>
</property>
</bean>
<bean id="audienceAdvisor"
class="org.springframework.
aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="audienceAdvice"/>
<property name="pattern" value=".*perform"/>
</bean>
</beans>
AudienceAdvice.java
public class AudienceAdvice implements MethodBeforeAdvice,
AfterReturningAdvice {
#Override
public void before(Method arg0, Object[] arg1, Object arg2)
throws Throwable {
audience.takeSeats();
audience.turnOffCellphones();
}
#Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2,
Object arg3) throws Throwable {
audience.applaud();
}
private Audience audience;
public void setAudience(Audience audience) {
this.audience = audience;
}
}
The AOP does not work but the target executes though.
You've declared the target bean and the advice, but by default Spring doesn't know to actually apply the advice to the target.
You need to run an Autoproxy.
One way to do this:
<!-- Autoproxy -->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>duke</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>audienceAdvisor</value>
</list>
</property>
</bean>