Retrieving property/value as string from Spring bean - java

I have the following in my context.xml:
<bean id="myBean" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>file:${specific.dir}/file1.properties</value>
<value>file:${specific.dir}/file2.properties</value>
<value>file:${specific.dir}/file3.properties</value>
<value>file:${specific.dir}/file4.properties</value>
</list>
</property>
</bean>
I am retrieving this bean in a POJO through a static spring application context, and going through the debugger this does seem to work.
Is there anyway for me to retrieve the four values in the list, and the property name in this POJO?
my staticSpringApplicationContext is as follows :
public class StaticSpringApplicationContext implements ApplicationContextAware {
private static ApplicationContext CONTEXT;
public void setApplicationContext(ApplicationContext context) throws BeansException {
CONTEXT = context;
}
public static Object getBean(String beanName) {
return CONTEXT.getBean(beanName);
}
}
and following this in my POJO I have:
StaticSpringApplicationContext.getBean("myBean");
Any help or guidance is greatly appreciated. I have had more trouble with Spring than I care to admit.

You can use spring #Value annotation, smth like this:
#Component
public MyClass {
#Value("${some.prop.name1}")
private String myProp1;
}
file1.properties:
some.prop.name1=value1
I hope it will be helpful. Good luck.

Whether you can do this will depend on the bean definition. It must have a setLocations() method (or be correctly annotated) via which Spring will inject the values.
You would retrieve the values using a getter method on the bean if one exists. If not you will need to modify the bean.

Related

injecting ConversionService into a custom Converter

Using Spring mvc-3. I am writing a custom Converter which needs access to other Converters registered to a ConversionService.
How can I accomplish this? I tried writing my custom converter as:
class CustomConverter<X, Y>{
#Autowired ConversionService service;
//+getter & setters of service
public Y convert(X input){
// I need access to service to lookup simple conversions such as
// String array to Long array etc..
}
}
And I registered my custom converter via applicationContext.xml
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name = "converters">
<list>
<bean class="CustomConverter"/>
</list>
</property>
</bean>
However, spring refuses to inject service into my CustomConverter(its always null). How can I accomplish this?
Thank you!
I have come across same problem. There's an issue SPR-6415 in Spring JIRA covering this problem. I've giving here my solution based on discussion in this issue. It's the same principle like answer of #nmervaillie but you don't have to implement your own ConversionServiceFactoryBean.
/**
* Base class of #{code Converter} that need to use {#code ConversionService}.
* Instances of implementing classes must be spring-managed to inject ConversionService.
*
* #author Michal Kreuzman
*/
public abstract class CoversionServiceAwareConverter<S, T> implements Converter<S, T> {
#Inject
private ConversionService conversionService;
protected ConversionService conversionService() {
return conversionService;
}
/**
* Add this converter to {#code ConverterRegistry}.
*/
#SuppressWarnings("unused")
#PostConstruct
private void register() {
if (conversionService instanceof ConverterRegistry) {
((ConverterRegistry) conversionService).addConverter(this);
} else {
throw new IllegalStateException("Can't register Converter to ConverterRegistry");
}
}
}
#Component
public class SampleConverter extends CoversionServiceAwareConverter<Object, Object> {
#Override
public String convert(Object source) {
ConversionService conversionService = conversionService();
// Use conversionService and convert
}
}
I have used something like this recently to solve this problem.
Use a custom factory :
public class MyConversionServiceFactoryBean extends ConversionServiceFactoryBean {
#Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
ConversionService conversionService = getObject();
ConverterRegistry registry = (ConverterRegistry) conversionService;
// register converters that need a nested conversion service
registry.addConverter(new MyCustomConverter(conversionService));
}
}
which is declared like this :
<bean id="conversionService"
class="com.company.MyConversionServiceFactoryBean">
<property name="converters">
<list>
... declare standard converters here ...
</list>
</property>
</bean>
I solved this problem in spring-ws centric application. The main components of this solutions are:
declaring Converter implementations as spring beans
using #Lazy from spring-context on the injection points in the converters
inject all discovered converters in a ConversionServiceFactoryBean
SampleConverter
#Component
public class SampleConverter implements Converter<Source, Target> {
private ConversionService conversionService;
#Inject
#Lazy
public SampleConverter(ConversionService conversionService){
this.conversionService = conversionService;
}
#Override
public Target convert(Source source){
Target target = new Target();
...
target.setTargetDetails(conversionService.convert(source.getSourceDetails, TargetDetails.class);
...
and the Configuration:
#Configuration
public class ConversionServiceConfig {
#Bean
public ConversionService conversionService(Set<Converter<?,?>> converters){
ConversionServiceFactoryBean csfb = new ConversionServiceFactoryBean();
csfb.setConverters(converters);
csfb.afterPropertiesSet();
return csfb.getObject();
}
...
The #Lazy annotations circumvents the egg-chicken problem by injecting a proxy and thus delaying the resolution of the conversionservice bean until it is really used.
Main problem (that i've encountered) is when you use ConversionServiceFactoryBean for building conversion service that includes converters that use conversion service as well is that you get error because of ConversionServiceFactoryBean.getObject method that provides instance of conversion service is being called prior to ConversionServiceFactoryBean.afterPropertiesSet where that conversion service instance is actually created.
So, to avoid this behavior, you just need to create conversion service prior to ConversionServiceFactoryBean.getObject is called. I've made it in constructor of class that extends ConversionServiceFactoryBean.
Example:
try {
Field serviceField = ConversionServiceFactoryBean.class.getDeclaredField("conversionService");
conversionServiceField.setAccessible(true);
conversionServiceField.set(this, createConversionService());
} catch (NoSuchFieldException | IllegalAccessException fieldAccessError) {
fieldAccessError.printStackTrace();
//or do some log output here, it's up to you
}
Than you can use converters that uses conversion service as well.
Hope it helps.

Spring JUnit4 manual-/auto-wiring dilemma

I ran into an issue that can only be explained with my fundamental lack of understanding of Spring's IoC container facilities and context setup, so I would ask for clarification regarding this.
Just for reference, an application I am maintaing has the following stack of technologies:
Java 1.6
Spring 2.5.6
RichFaces 3.3.1-GA UI
Spring framework is used for bean management with Spring JDBC module used for DAO support
Maven is used as build manager
JUnit 4.4 is now introduced as test engine
I am retroactively (sic!) writing JUnit tests for the application and what suprised me is that I wasn't able to inject a bean into a test class by using setter injection without resorting to #Autowire notation.
Let me provide set up an example and accompanying configuration files.
The test class TypeTest is really simple:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class TypeTest {
#Autowired
private IType type;
#Test
public void testFindAllTypes() {
List<Type> result;
try {
result = type.findAlltTypes();
assertNotNull(result);
} catch (Exception e) {
e.printStackTrace();
fail("Exception caught with " + e.getMessage());
}
}
}
Its context is defined in TestStackOverflowExample-context.xml:
<context:property-placeholder location="classpath:testContext.properties" />
<context:annotation-config />
<tx:annotation-driven />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${db.connection.driver.class}" />
<property name="url" value="${db.connection.url}" />
<property name="username" value="${db.connection.username}" />
<property name="password" value="${db.connection.password}" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="beanDAO" class="com.example.BeanDAOImpl">
<property name="ds" ref="dataSource"></property>
<property name="beanDAOTwo" ref="beanDAOTwo"></property>
</bean>
<bean id="beanDAOTwo" class="com.example.BeanDAOTwoImpl">
<property name="ds" ref="dataSource"></property>
</bean>
<bean id="type" class="com.example.TypeImpl">
<property name="beanDAO" ref="beanDAO"></property>
</bean>
TestContext.properties is in classpath and contains only db-specific data needed for datasource.
This works like a charm but my question is - why doesn't it work when I try to manually wire beans and perform setter injection as in:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class TypeTest {
private IType type;
public IType getType () {
return type;
}
public void setType(IType type) {
this.type= type;
}
#Test
public void testFindAllTypes(){
//snip, snip...
}
}
What am I missing here? What part of configuration is wrong here? When I try to manually inject beans via setters, test fails because this part
result = type.findAlltTypes();
is resolved as null in runtime. I've, of course, consulted the Spring reference manual and tried various combinations of XML configuration; all I could conclude is that Spring was unable to inject beans because it somehow fails to properly dereference Spring Test Context reference but by using #Autowired this happens "automagically" and I really can't see why is that because JavaDoc of both Autowired annotation and its PostProcessor class doesn't mention this.
Also worth adding is the fact that #Autowired is used in application only here. Elsewhere only manual wiring is performed, so this also brings forth question - why is it working there and not here, in my test? What part of DI configuration am I missing? How does #Autowired get reference of Spring Context?
EDIT:
I've also tried this but with same results:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class TypeTest implements ApplicationContextAware{
private IType type;
private ApplicationContext ctx;
public TypeTest(){
super();
ctx = new FileSystemXmlApplicationContext("/TypeTest-context.xml");
ctx.getBean("type");
}
public IType getType () {
return type;
}
public void setType(IType type) {
this.type= type;
}
#Test
public void testFindAllTypes(){
//snip, snip...
}
}
Any other ideas, perhaps?
EDIT2:
I've found a way without resorting to writing own TestContextListener or BeanPostProcessor. It is suprisingly simple and it turns out that I was on the right track with my last edit:
1) Constructor-based context resolving:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class TypeTest{
private IType type;
private ApplicationContext ctx;
public TypeTest(){
super();
ctx = new FileSystemXmlApplicationContext("/TypeTest-context.xml");
type = ctx.getBean("type");
}
public IType getType () {
return type;
}
public void setType(IType type) {
this.type= type;
}
#Test
public void testFindAllTypes(){
//snip, snip...
}
}
2) By implementing ApplicationContextAware interface:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class TypeTest implements ApplicationContextAware{
private IType type;
private ApplicationContext ctx;
public IType getType () {
return type;
}
public void setType(IType type) {
this.type= type;
}
#Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
this.ctx = ctx;
type = (Type) ctx.getBean("type");
}
#Test
public void testFindAllTypes(){
//snip, snip...
}
}
Both of these approaches properly instanced beans.
If you take a look at the source of org.springframework.test.context.support.DependencyInjectionTestExecutionListener, you will see the following method (formatted and commented for clarity):
protected void injectDependencies(final TestContext testContext)
throws Exception {
Object bean = testContext.getTestInstance();
AutowireCapableBeanFactory beanFactory = testContext.getApplicationContext()
.getAutowireCapableBeanFactory();
beanFactory.autowireBeanProperties(bean,
AutowireCapableBeanFactory.AUTOWIRE_NO,
// no autowiring!!!!!!!!
false
);
beanFactory.initializeBean(bean, testContext.getTestClass().getName());
// but here, bean post processors are run
testContext.removeAttribute(REINJECT_DEPENDENCIES_ATTRIBUTE);
}
So the test object is a bean without auto-wiring. However, #AutoWired, #Resource etc, don't use the autowiring mechanism, they use BeanPostProcessor. And so the dependencies are injected if and only if the annotations are used (or if you register some other BeanPostProcessor that does it).
(The above code is from Spring 3.0.x, but I bet it was the same in 2.5.x)

Prototype scope not working

I've created a prototype scoped bean in my application and I'm injecting that to another bean using a setter. But when I'm using the injected bean in my class it is always using the same instance instead of new instance every time.
Here is a snapshot of the code
<bean name="prototypeScope" Class="A" scope="prototype">
</bean>
<bean Class="Consumer">
<property name="a" ref="prototypeScope" />
</bean>
public class Consumer{
privare A a;
public void setA(A a){
this.a = a;
}
public void consume(){
a.doSomething();
}
}
Regards
It is an common mistake related to prototype scoped beans.
A new instance of the prototype scoped bean will be created only when we request a copy of the bean from the application context, not every time we call a method on the instance.
In your case you are injecting the prototype scoped bean to another bean using the setter of the later, so then the second class is created a new instance of the prototype scoped bean will be created. But it will use the same instance as long as it is replace by another instace mannualy by you.
If you want a new instance of the prototype scoped bean during a particular operation like a method call, you have to get a new instance of the bean from the application content.
Ex:
<bean name="prototypeScope" Class="A" scope="prototype">
</bean>
<bean Class="Consumer">
</bean>
Java code:
public class Consumer implements ApplicationContextAware{
privare ApplicationContext context;
public void setApplicationContext(ApplicationContext context){
this.context = context;
}
public void consume(){
A a = context.getBean("prototypeScope", A.class);
a.doSomething();
}
}
In this example when ever the consume method is called a new instance of class A is created.
There are two main ways to deal with the Singleton-Bean-has-Prototype-dependency problem.
One is tight coupling to the applicationContext, as in Ram's answer, the other is Lookup Method Injection.
Basically, you make your bean class abstract and add an abstract method for the dependency, something like this:
public abstract class MyBean{
public abstract MyService lookupService();
}
Then you add a bean definition something like this:
<bean id="myBean" class="fiona.apple.sucks.MyBean">
<!-- sorry, just wanted to insert sucks after Spring's fiona apple example,
didn't think about the connotations :-) -->
<lookup-method name="lookupService"/>
</bean>
Now Spring will create a CGLib subclass of your bean class that will return a new Prototype instance for every time you call myBean.lookupService().
I used such approach once..
First I declared a bean
<bean id="notSingelton" class="com.Foo" singleton="false" />
Then made an interface
public interface FooFactory {
Foo make(String name);
}
wrapped it into ServiceLocatorFactoryBean
<bean id="fooFactory"
class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
<property name="serviceLocatorInterface" value="com.FooFactory" />
</bean>
<bean id="consumer" class="com.Consumer">
<constructor-arg ref="fooFactory" />
</bean>
And consumer class looked something like that:
public class Consumer {
private FooFactory fooFactory;
public Consumer(FooFactory fooFactory) {
this.fooFactory = fooFactory;
}
public void consume(){
Foo foo = fooFactory.make("notSingelton");
foo.doSomething();
}
}

How to collect and inject all beans of a given type in Spring XML configuration

One of the strongest accents of the Spring framework is the Dependency Injection concept. I understand one of the advices behind that is to separate general high-level mechanism from low-level details (as announced by Dependency Inversion Principle).
Technically, that boils down to having a bean implementation to know as little as possible about a bean being injected as a dependency, e.g.
public class PrintOutBean {
private LogicBean logicBean;
public void action() {
System.out.println(logicBean.humanReadableDetails());
}
//...
}
<bean class="PrintOutBean">
<property name="loginBean" ref="ShoppingCartBean"/>
</bean>
But what if I wanted to a have a high-level mechanism operating on multiple dependent beans?
public class MenuManagementBean {
private Collection<Option> options;
public void printOut() {
for (Option option:options) {
// do something for option
}
//...
}
}
I know one solution would be to use #Autowired annotation in the singleton bean, that is...
#Autowired
private Collection<Option> options;
But doesn't it violate the separation principle? Why do I have to specify what dependents to take in the very same place I use them (i.e. MenuManagementBean class in my example)?
Is there a way to inject collections of beans in the XML configuration like this (without any annotation in the MMB class)?
<bean class="MenuManagementBean">
<property name="options">
<xxx:autowire by-type="MyOptionImpl"/>
</property>
</bean>
Old question and in Spring 3.1 it is possible:
public class PluginPrototypeTest extends ASpringWebTest {
#Autowired
Collection<IDummyRepo> repos;
#Test
public void cacheTest() {
assertNotNull(repos);
assertEquals(2, repos.size());
for(IDummyRepo r: repos){
System.out.println(r.getName());
}
}
}
#Repository
public class DummyRepo implements IDummyRepo {
#Override
public String getName(){
return "DummyRepo";
}
}
#Repository
public class DummyRepo2 implements IDummyRepo {
#Override
public String getName(){
return "DummyRepo2";
}
}
There's no out-of-the-box facility to do this, no. However, if you want a way of collecting all beans of a given type into a collection, without using an #Autowired list, then it's easy to write a custom FactoryBean to do it for you:
public class BeanListFactoryBean<T> extends AbstractFactoryBean<Collection<T>> {
private Class<T> beanType;
private #Autowired ListableBeanFactory beanFactory;
#Required
public void setBeanType(Class<T> beanType) {
this.beanType = beanType;
}
#Override
protected Collection<T> createInstance() throws Exception {
return beanFactory.getBeansOfType(beanType).values();
}
#Override
public Class<?> getObjectType() {
return Collection.class;
}
}
and then
<bean class="MenuManagementBean">
<property name="options">
<bean class="BeanListFactoryBean">
<property name="beanType" class="MyOptionImpl.class"/>
</bean>
</property>
</bean>
However, this all seems like a lot of effort to avoid putting #Autowired in your original class. It's not much of a violation of SoC, if it is at all - there's no compiltime dependency, and no knowledge of where the options are coming from.
Alternative to #Autowired, using a context file: http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-autowire
So you'd have:
<bean class="MenuManagementBean" autowire="byType" />
Other properties can be specified, as normal, and that would override the autowiring only for those properties.

Intentionally setting a Spring bean to null

I'm using Spring to inject JMS connection factory into my Java application. Since this factory is only required within the production environment, not while I'm developing though, I put the bean definition into a separate XML which I include into my main applicationContext.xml. In production environments this extra file contains the regular bean definition. In my local dev environment I'd like this bean to be null. Trying to simply remove the bean definition all-toghether obviously caused an error when Spring came across a reference ID it didn't know.
So I tried creating a factory bean that would simply return null. If I do this, Spring (2.5.x) complains that the factory returned null although based on the Spring API doc of the FactoryBean interface I expected this to work (see Spring API doc).
The XML looks something like this:
<bean id="jmsConnectionFactoryFactory" class="de.airlinesim.jms.NullJmsConnectionFactoryFactory" />
<bean id="jmsConnectionFactory" factory-bean="jmsConnectionFactoryFactory" factory-method="getObject"/>
What would be the "correct" way of doing this?
I'm pretty sure that Spring won't allow you to associate null with a bean id or alias. You can handle this by setting properties to null.
Here's how you did this in Spring 2.5
<bean class="ExampleBean">
<property name="email"><null/></property>
</bean>
In Spring 3.0, you should also be able to use the Spring expression language (SpEL); e.g.
<bean class="ExampleBean">
<property name="email" value="#{ null }"/>
</bean>
or any SpEL expression that evaluates to null.
And if you are using a placeholder configurator you could possibly even do this:
<bean class="ExampleBean">
<property name="email" value="#{ ${some.prop} }`"/>
</bean>
where some.prop could be defined in a property file as:
some.prop=null
or
some.prop=some.bean.id
factory-bean/factory-method doesn't work with null, but a custom FactoryBean implementation works fine:
public class NullFactoryBean implements FactoryBean<Void> {
public Void getObject() throws Exception {
return null;
}
public Class<? extends Void> getObjectType() {
return null;
}
public boolean isSingleton() {
return true;
}
}
<bean id="jmsConnectionFactory" class = "com.sample.NullFactoryBean" />
For anyone coming to this question, keep in mind that simply setting the #Autowired annotation as optional will do the trick (i.e. Spring will leave the reference null if no qualifying bean is found).
#Autowired(required = false)
private SomeClass someBean
Note that you would have to do this everywhere the bean is referenced, which may be a bigger hassle than creating a null-factory as mentioned above.
For anyone else who comes across this: another approach if you're using Java 8 is to use the Supplier functional interface to wrap a potentially null bean:
#Bean
#Scope("singleton")
public Supplier<SomeBean> getSomeBean() {
SomeBean myBean = null; // or can set to a SomeBean instance
return () -> myBean;
}
With #Autowired constructor injection using this looks like:
private SomeBean someBean;
#Autowired
SomeService(Supplier<SomeBean> someBeanSupplier) {
this.someBean = someBeanSupplier.get();
}
Then the someBean field in SomeService can either be null or non-null.
Some noted above, axtact's answer doesn't work in Autowiring contextes, where Spring will rely on correct information from the getObjectType() method. So you might end up with errors like:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [xxxxxxxxxxxxx] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true), #org.springframework.beans.factory.annotation.Qualifier(value=yyyyyyyyyyyyyyyy)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:920)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:789)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:703)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotatio
So here's a small variation which involves allowing users to force the objectype at construction. Using a property instead of a constructor-arg didn't work because Spring doesn't fully initialize the beans in this context.
public class NullFactoryBean implements FactoryBean {
private final Class<?> objectType;
public NullFactoryBean(Class<?> objectType) {
this.objectType = objectType;
}
#Override
public Object getObject() throws Exception {
return null;
}
#Override
public Class<?> getObjectType() {
return objectType;
}
#Override
public boolean isSingleton() {
return false;
}
}
In tests null beans can also be injected like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = NullTest.class)
#Configuration
public class NullTest {
#Bean(name = "em")
public IEntityManager em() { return null; }
#Bean
public PlatformTransactionManager tm() { return null; }
#Resource
private SomeBean someBean; // this would get em and tm fields autowired to nulls
Can you make use of the special <null> bean element ? e.g.
<bean class="ExampleBean">
<property name="email"><null/></property>
</bean>
from the doc, section 3.3.2.5

Categories

Resources