injecting ConversionService into a custom Converter - java

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.

Related

Spring - ConversionService no #Autowired because of ConfigurationPropertiesBindingPostProcessor

i've found a problem when using the Spring ConversionService (first I thought this was related to my test, but this was my error, it happens always). I try to create it via...
#Configuration
#ComponentScan(basePackages={"com.mybasepacke"})
public class MyConfiguration {
#Bean
#SuppressWarnings("rawtypes")
public ConversionServiceFactoryBean conversionService(ApplicationContext context) {
ConversionServiceFactoryBean factory = new ConversionServiceFactoryBean();
Map<String, MyConverter> converters = context.getBeansOfType(MyConverter.class);
factory.setConverters(new HashSet<>(converters.values()));
factory.afterPropertiesSet();
return factory;
}
}
This way, I expect to be able to simply create Converters (MyConverter is just a marker interface that extends Spring's Converter) like this...
#Component
public class ExampleConverter implements MyConverter<Something, SomethingElse> {
#Autowired
private SomeService someService;
... }
Spring should find all the MyConverters, add them all to the ConversionService (Factory) and I'll be able to use them... Theoretically. In reality, this happens:
ConfigurationPropertiesBindingPostProcessor gets initialized.
It optionally depends on a ConversionService.
Spring finds my ConversionServiceFactoryBean definition and starts it.
Unfortunately, ConfigurationPropertiesBindingPostProcessor is created BEFORE the AutowiredAnnotationBeanPostProcessor is registered. So all of its dependencies are NOT autowired. Which leads to all my converters not being autowired.
Has anyone an idea how to prevent this behavior? Or do I have to get rid of ConversionService since it doesn't seem to be able to use Converters with autowired fields?
Don't name your ConversionService conversionService, check the doc that basically explains what you found out yourself.
#Bean
public ConversionService myConversionService() {
// your setup
}
This is going to register a myConversionService (notice the method name) that will not be eagerly loaded by the configuration stuff. If you need some converters to coerce value from configuration (as defined in the doc), consider marking those converters with ConfigurationPropertiesBinding:
#Component
#ConfigurationPropertiesBinding
// This can't autowire things either ...
public class ExampleConverter implements MyConverter<Something, SomethingElse> { ... }

Injecting object into Spring Configuration

I am turning old xml/java configuration into pure java config. In xml I used injection of parameters into configuration file like this:
<bean class="com.project.SpringRestConfiguration">
<property name="parameters" ref="parameters" />
</bean>
#Configuration
public class SpringRestConfiguration {
private Parameters parameters;
public void setParameters(Parameters parameters) {
this.parameters = parameters;
}
// #Bean definitions
...
}
Is it possible to inject Parameters in javaconfig? (Without the need of using autowiring!)
#Configuration
#Import(SpringRestConfiguration.class)
EDIT:
With #Import I can't see any chance to inject Parameters into SpringRestConfiguration
Basically you would need to use #Autowired but you can still use a name and not type interpretation like this:
#Configuration
public class SpringRestConfiguration {
#Autowired
#Qualifier("parameters") // Somewhere in your context you should have a bean named 'parameters'. It doesn't matter if it was defined with XML, configuration class or with auto scanning. As long as such bean with the right type and name exists, you should be good.
private Parameters parameters;
// #Bean definitions
...
}
This solves the confusion problem you mentioned when using #Autowired - there's no question here which bean is injected, the bean that is named parameters.
You can even do a little test, leave the parameters bean defined in the XML as before, use #Autowired, see that it works. Only then migrate parameters to #Configuration class.
In my answer here you can find a complete explanation of how you should migrate XML to #Configuration step by step.
You can also skip the private member altogether and do something like this:
#Configuration
public class SpringRestConfiguration {
#Bean
public BeanThatNeedsParamters beanThatNeedsParamters (#Qualifier("parameters") Parameters parameters) {
return new BeanThatNeedsParamters(parameters)
}
}
If I have understood your question properly, this is what you are trying to do :
#Component
public class SomeConfiguration {
#Bean(name="parameters")
public Parameters getParameters(){
Parameters parameters = new Parameters();
// add your stuff
return parameters;
}
#Bean(name="springRestConfiguration")
public SpringRestConfiguration springRestConfiguration(){
SpringRestConfiguration springRestConfiguration = new SpringRestConfiguration();
springRestConfiguration.setParametere(getParameters());
return springRestConfiguration;
}
}
and use it like :
ApplicationContext appContext = new AnnotationConfigApplicationContext(SomeConfiguration.class);
SpringRestConfiguration springRestConfiguration = (SpringRestConfiguration) appContext.getBean("springRestConfiguration");

Defining the request scope as prototype for integration tests

When writing integration tests with Spring 3.1, I usually define the request scope to be a SimpleThreadScope, with the following XML context configuration:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="request">
<bean class="org.springframework.context.support.SimpleThreadScope" />
</entry>
</map>
</property>
</bean>
To define the request scope to be backed by a prototype scope implementation, I thought to change the class to be an implementation of the prototype scope. However I was not able to locate any.
Looking at the Scope Interface Javadoc, in the section All Known Implementing Classes, I see listed: AbstractRequestAttributesScope, PortletContextScope, RequestScope, ServletContextScope, SessionScope, SimpleThreadScope... nothing that looks like a prototype scope.
How can I define the request scope as prototype for integration tests?
UPDATE: I've managed to make my integration tests pass by creating my own prototype scope, which I've defined as follow, so my question now is, whether the following implementation is correct, or it has to be fixed.
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
public class PrototypeScope implements Scope {
private static final Log logger = LogFactory.getLog(PrototypeScope.class);
public Object get(String name, ObjectFactory objectFactory) {
return objectFactory.getObject();
}
public Object remove(String name) {
return null;
}
public void registerDestructionCallback(String name, Runnable callback) {
logger.warn("PrototypeScope does not support destruction callbacks. "
+ "Consider using a RequestScope in a Web environment.");
}
public Object resolveContextualObject(String key) {
return null;
}
public String getConversationId() {
return Thread.currentThread().getName();
}
}
UPDATE 2: I am using TestNG and my Integration tests look like this:
#Test
#ContextConfiguration(locations = { "classpath:META-INF/spring/test-context.xml" })
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class MyIntegrationTest extends AbstractTransactionalTestNGSpringContextTests {
#Resource
private MyBeanThatShouldBePrototype bean;
#Transactional
public void testCase() {
...
In fact it's working in a different way - Spring checks if bean is a prototype, and then clones its definition and just populate new bean, so there is no backing class for holding such beans. If you want to look at the implementation please visit:
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean and you will find:
if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
If you want to use prototype scope in tests you can just manually create this bean by invoking new MyObjectThatShouldBePrototype() and then configure it as a Spring bean by using AutowireCapableBeanFactory (injected/autowired into your test):
#Autowired
AutowireCapableBeanFactory beanFactory;
public MyObjectThatShouldBePrototype getBean() {
MyObjectThatShouldBePrototype bean = new MyObjectThatShouldBePrototype();
beanFactory.autowireBean(bean);
return bean;
}
Of course there are several ways to create beans - you can find then here http://www.kubrynski.com/2013/09/injecting-spring-dependencies-into-non.html
Something like this is not working for you?
#Test
#ContextConfiguration(locations = { "classpath:META-INF/spring/test-context.xml" },
classes = MyIntegrationTest.TestConfig.class)
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class MyIntegrationTest extends AbstractTransactionalTestNGSpringContextTests {
#Resource
private MyBeanThatShouldBePrototype bean; // protype bean produced by spring
#Transactional
public void testCase() {
...
}
#Configuration
public static class TestConfig {
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public MyBeanThatShouldBePrototype myBeanThatShouldBePrototype() {
return new MyBeanThatShouldBePrototype();
}
}
}
Probably you could go another way?
What about writing a beanfactorypostprocessor that changes the request scoped bean candidates to prototype instead?
I havent tried it myself but you should be able to apply this to any bean declared as request scoped and set the prototype flag.
In the spring context for your unit tests you define this processor and in the context for integration tests this postprocessor would not be around.

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