How to set Class value to spring bean property? - java

Hey, what is the best way to set a bean's property with Class value ? Regarding XML configuration. For a bean like this :
public class FilterJsonView extends MappingJacksonJsonView {
private Set<String> filteredAttributes;
private Class clazz;
public Set<String> getFilteredAttributes() {
return filteredAttributes;
}
public void setFilteredAttributes(Set<String> filteredAttributes) {
this.filteredAttributes = filteredAttributes;
}
public Class getClazz() {
return clazz;
}
public void setClazz(Class clazz) {
this.clazz = clazz;
}
}

Just inject the class name, and Spring will convert it to a Class object for you, e.g.
<bean class="com.x.y.FilterJsonView">
<property name="clazz" value="com.x.y.SomeClass"/>
</bean>

Just supply the class name. Say you want clazz to be String.class:
<bean id="beanId" class="FilterJsonView">
<property name="clazz" value="java.lang.String"/>
</bean>
Spring has a PropertyEditorSupport implementation called ClassEditor that handles the conversions.

Related

How to generate a list of beans dynamically

Hy
I'm looking for a way to 'simplify'/shorten my spring configuration.
I' ve got this Generic service that looks something like:
public class GenericService<T> {
private Class<T> targetClass;
public void setTargetClass(Class<T> targetClass) {this.targetClass = targetClass;}
public void doSomething() {...}
}
and in my spring-config.xml file I have
<bean id="entity1Service" class="GenericService">
<property name="targetClass" value="model.Entity1" />
</bean>
<bean id="entity2Service" class="GenericService">
<property name="targetClass" value="model.Entity2" />
</bean>
...
I'm trying to build a factory that will build all these services for me so that I could write something like this in my spring-config.xml
<bean class="ServiceFactory">
<property name="targets">
<list>
<value>model.Entity1</value>
<value>model.Entity2</value>
</list>
</property>
</bean>
which would generate 2 beans (one named entity1Service, the other entity2Service). Get-it?
How would I start? I've looked at BeanFactory (not to be confused with FactoryBean!) but fail to see how to hookup everything up.
It would be even better if my factory could scan my packages and generate a service when it finds an entity (either through annotation or interface implementation), a little like #EnableJpaRepositories annotation in spring-data does for all JpaRepository interfaces.
Thanks for any insights, examples, pointers...
w.
I believe I've figured it out and posting my result for future references.
public class GenericBeanGenerator <T, G> implements BeanFactoryPostProcessor, BeanPostProcessor {
/**
* The type of the bean to create
*/
private Class<T> type;
/**
* The list of generic values. Can be String, Class or whatever
*/
private Iterable<G> generics;
private Map<String, G> beanNameToGeneric = new HashMap<String, G>();
public GenericBeanGenerator(Class<T> type, G[] generics) {
this.type = type;
this.generics = Arrays.asList(generics);
}
public GenericBeanGenerator(Class<T> type, Iterable<G> generics) {
this.type = type;
this.generics = generics;
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// for each 'generic' value, add a bean definition to the beanFactory with the appropriate bean name
for(G generic : generics) {
String beanName = getBeanName(generic);
beanNameToGeneric.put(beanName, generic);
((DefaultListableBeanFactory) beanFactory).registerBeanDefinition(beanName, new AnnotatedGenericBeanDefinition(type) );
}
}
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (type.isInstance(bean) && beanNameToGeneric.containsKey(beanName)) {
#SuppressWarnings("unchecked")
T instance = (T) bean;
initiliaze(beanName, beanNameToGeneric.get(beanName), instance);
}
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
* Convert a 'generic' value to a string in order to name the bean
*/
public String getBeanName(G generic) {
return generic.toString();
}
/**
* Initialize the bean if needed.
*/
public void initiliaze(String beanName, G generic, T instance) {
}
}
Now if I want a number of generics services that extends a class like...
class GenericService<T> {
Class<T> entityClass;
public void setEntityClass(Class<T> clazz) {
this.entityClass = clazz;
}
....
}
I could have something like this in one of my #Configuration beans
class Config {
#Bean
public static GenericBeanGenerator<GenericService, Class<?>> genericServiceGenerator() {
List<Class<?>> entities = Arrays.asList(A.class, B.class);
return new GenericBeanGenerator<GenericService, Class<?>>(GenericService.class, entities) {
#Override
public String getBeanName(Class<?> generic) {
return generic.getSimpleName() + "Service";
}
#Override
public void initiliaze(String beanName, Class<?> generic, GenericService instance) {
instance.setEntityClass(generic);
}
};
}
}
This would generate two beans named AService and BService for my entities A and B.
And even more powerfull: If my entities all implement an interface named Idable, I could generate all my service beans if I used something like this to scan my packages:
BeanDefinitionRegistry bdr = new SimpleBeanDefinitionRegistry();
ClassPathBeanDefinitionScanner s = new ClassPathBeanDefinitionScanner(bdr);
TypeFilter tf = new AssignableTypeFilter(Idable.class);
s.addIncludeFilter(tf);
s.scan("org.willix.model");
entities = bdr.getBeanDefinitionNames();
You can try doing it programmatically:
public class Application {
#Autowired
private ApplicationContext applicationContext;
public void loadBeans() {
NewBean newBean = applicationContext.getAutowireCapableBeanFactory().createBean(NewBean.class);
}
}
You should also be able to autowire these beans after they have been created.
Edit:
You can name these beans using an annotation in the bean's class:
#Component("NewBean1")
public class NewBean1 implements GenericService<T> {
}
And then when you autowire it, use the #Qualifier annotation
public class BeanController {
#Autowired
#Qualifier("NewBean1")
private GenericService<T> bean;
}

Spring Formatter for field annotation not work in Web Flow

Using spring web flow 2,
Formatter by field type is effective
but Formatter for Field Annotation is not.
getPrint and getParser not called.
(by field type, they are called)
I've spent much time about this,
but have no good results.
Bean for page
public TestBean {
#TestFormat
private String test;
...
}
Annotation
#Target({ElementType.TYPE,ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
public #interface TestFormat {}
AnnotationFormatterFactory
public class TestFormatAnnotationFormatterFactory implements AnnotationFormatterFactory<TestFormat>,Serializable {
#Override
public Set<Class<?>> getFieldTypes() {
Set<Class<?>> set = new HashSet<Class<?>>();
set.add(TestFormat.class);
return set;
}
#Override
public Printer<?> getPrinter(TestFormat annotation, Class<?> fieldType) {
return new TestFormatter();
}
#Override
public Parser<?> getParser(TestFormat annotation, Class<?> fieldType) {
return new TestFormatter();
}
}
Formatter
public class TestFormatter implements Formatter<String>{
#Override
public String print(String str, Locale locale) {
return str.substring(0, str.indexOf("parsed")); // example
}
#Override
public String parse(String input, Locale locale) throws ParseException {
return input + "parsed"; // example
}
}
ApplicationFormatterRegistrar
public class ApplicationFormatterRegistrar implements FormatterRegistrar {
#Override
public void registerFormatters(FormatterRegistry registry) {
registry.addFormatterForFieldAnnotation(new TestFormatAnnotationFormatterFactory());
}
}
SpringMVC Configuration
<bean id="applicationConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatterRegistrars">
<set>
<ref local="applicationFormatterRegistrar"/>
</set>
</property>
</bean>
<bean id="applicationFormatterRegistrar" class="package.ApplicationFormatterRegistrar"/>
Spring Webflow Configuration
<bean id="defaultConversionService" class="org.springframework.binding.convert.service.DefaultConversionService" >
<constructor-arg ref="applicationConversionService"/>
</bean>
<webflow:flow-builder-services id="flowBuilderServices" conversion-service="defaultConversionService"/>
this might be related, but I could not find a
solution
Spring Web Flow 2.4.1
Spring 4.1.6
Thymeleaf 2.1.4
When implementing the AnnotationFormatterFactory then its getFieldTypes method should return the type of the fields the annotation applies to. With your current configuration you are saying TestFormat can be annotated with TestFormat.
I suspect however that you want to specify String can be annotated with TestFormat.
Change your implementation to return String.class instead.
public class TestFormatAnnotationFormatterFactory implements AnnotationFormatterFactory<TestFormat>,Serializable {
#Override
public Set<Class<?>> getFieldTypes() {
return Collections.singleton(String.class);
}
...
}

How to set MDB programmatic and dynamically

I am using Spring3.1 on standalone env.
I set topic with jms templates this way:
<bean id="mm1sessionsTopicSendingTemplate" class="org.springframework.jndi.JndiObjectFactoryBean"
depends-on="jmsServerManagerImpl">
<property name="jndiName">
<value>/topic/mm1sessionsTopic</value>
</property>
</bean>
For this topic I set MDB with DefaultMessageListenerContainer this way:
<bean id="mm1sessionDispatcherListener"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="pubSubDomain" value="true" />
<property name="concurrentConsumers" value="1" />
<property name="destination" ref="mm1sessionsTopicSendingTemplate" />
<property name="messageListener" ref="mm1SessionMDB" />
<property name="sessionAcknowledgeModeName" value="AUTO_ACKNOWLEDGE" />
</bean>
In this way I must set mm1SessionMDB in advanced via xml:
<bean id="mm1SessionMDB" class="com.mdb.SessionMDB">
<property name="feedPropertiesDTO" ref="feedListenerMarketMaker1Properties" />
</bean>
But I need my application to create the MDB instances programmaticly.
I mean i want to create the mdb's via the code since each MDB will have different validation values for the messages that it will retrieve from the topic(via the feedPropertiesDTO)
basically I will have pool of MDB's with the same logic but each one will have different properties. the creation time of the MDB'S must be on runtime.
is that possible?
thanks,
ray.
I think you can use factory method for instantating your MDB bean and use method
Object getBean(String name, Object... args) throws BeansException;
of the ApplicationContext in your code to instantiate bean frogramatically.
As I know this method allows you to path argument to factory method.
Here what is said in java doc for this method:
Return an instance, which may be shared or independent, of the specified bean.
Allows for specifying explicit constructor arguments / factory method
arguments, overriding the specified default arguments (if any) in the
bean definition.
I have never used this approach but I think it colud work for your case.
EDIT.
Here is an example that demonstrates about what I'm talkin (It is very simple but I don't have enough time to write more complicated).
Suppose that have interface and two it's implementations:
public interface StringMakerInterface {
// Just return simple String depending on concrete implementation.
String returnDummyString();
}
public class StringMakerImpl1 implements StringMakerInterface {
public String returnDummyString() {
return "test bean impl 1";
}
}
public class StringMakerImpl2 implements StringMakerInterface{
public String returnDummyString() {
return "test bean impl 2";
}
}
And we have one class that uses concrete implementation of this interface and to which we should dinamically inject conctrete implementation:
public class StringPrinter {
private StringMakerInterface stringMaker;
public StringMakerInterface getStringMaker() {
return stringMaker;
}
public void setStringMaker(StringMakerInterface stringMaker) {
this.stringMaker = stringMaker;
}
public StringPrinter() {
}
// Just print dummy string, returned by implementation
public void printString() {
System.out.println(stringMaker.returnDummyString());
}
}
Here is configuration class for my example:
#Configuration
public class TestFactoryMethodConfig {
#Bean(name = "stringMaker1")
public StringMakerImpl1 stringMaker1() {
return new StringMakerImpl1();
}
#Bean(name = "stringMaker2")
public StringMakerImpl2 stringMaker2() {
return new StringMakerImpl2();
}
#Bean(name = "stringPrinter")
#Scope(value = "prototype")
public StringPrinter stringPrinter(#Qualifier("stringMaker1") StringMakerInterface stringMaker) {
StringPrinter instance = new StringPrinter();
instance.setStringMaker(stringMaker);
return instance;
}
}
And here is a test case that demonstrates dinamically injection at the runtime:
#RunWith(value = SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes={TestFactoryMethodConfig.class})
public class TestFactoryMethod {
#Autowired
private ApplicationContext applicationContext;
#Resource(name = "stringMaker1")
private StringMakerInterface stringMaker1;
#Resource(name = "stringMaker2")
private StringMakerInterface stringMaker2;
#Test
public void testFactoryMethodUsage() {
StringPrinter stringPrinter1 = (StringPrinter) applicationContext.getBean("stringPrinter", stringMaker1);
StringPrinter stringPrinter2 = (StringPrinter) applicationContext.getBean("stringPrinter", stringMaker2);
stringPrinter1.printString();
stringPrinter2.printString();
}
}

Two-way converter in spring

Spring 3 has such a nice feature as type conversion. It provides a converter SPI(Converter<S, T>) to be used to implement differenet conversion logic.
The subclass of Converter type allow to define one-way conversion(only from S to T), so if I want a conversion also to be performed from T to S I need to define another converter class that implement Converter<T, S>. If I have many classes which are subject to conversion, i need to define many converters.
Is there any posibility to define two-way conversion logic(from S to T and from T to S) in one converter? and how it will be used?
PS. now I'm using my converters via ConversionServiceFactoryBean defining/injecting them in configuration file
You are correct, if you want to use the org.springframework.core.convert.converter.Converter interface directly, you'll need to implement two converters, one for each direction.
But spring 3 has a couple of other options:
If your conversion is not object-to-object but rather object-to-string (and back), then you can implement a org.springframework.format.Formatter instead. Formatters get registered as GenericConverters (see http://static.springsource.org/spring-webflow/docs/2.3.x/reference/html/ch05s07.html#converter-upgrade-to-spring-3)
Otherwise you could implement your own org.springframework.core.convert.converter.GenericConverter, which makes it easy to create TwoWayConverter implementations using reflection.
public abstract class AbstractTwoWayConverter<S, T> implements GenericConverter {
private Class<S> classOfS;
private Class<T> classOfT;
protected AbstractTwoWayConverter() {
Type typeA = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
Type typeB = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
this.classOfS = (Class) typeA;
this.classOfT = (Class) typeB;
}
public Set<ConvertiblePair> getConvertibleTypes() {
Set<ConvertiblePair> convertiblePairs = new HashSet<ConvertiblePair>();
convertiblePairs.add(new ConvertiblePair(classOfS, classOfT));
convertiblePairs.add(new ConvertiblePair(classOfT, classOfS));
return convertiblePairs;
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (classOfS.equals(sourceType.getType())) {
return this.convert((S) source);
} else {
return this.convertBack((T) source);
}
}
protected abstract T convert(S source);
protected abstract S convertBack(T target);
}
/**
* converter to convert between a userId and user.
* this class can be registered like so:
* conversionService.addConverter(new UserIdConverter (userDao));
*/
public class UserIdConverter extends AbstractTwoWayConverter<String, User> {
private final UserDao userDao;
#Autowired
public UserIdConverter(UserDao userDao) {
this.userDao = userDao;
}
#Override
protected User convert(String userId) {
return userDao.load(userId);
}
#Override
protected String convertBack(User target) {
return target.getUserId();
}
}
Spring has just such an interface for this purpose: TwoWayConverter.
see the following:
http://static.springsource.org/spring-webflow/docs/2.0.x/javadoc-api/org/springframework/binding/convert/converters/TwoWayConverter.html
You can use Spring Formatter to format object of type T to String and vice versa.
package org.springframework.format;
public interface Formatter<T> extends Printer<T>, Parser<T> {
}
Using this interface you can achieve the same as the Barry Pitman says but with less code and this is the preferable way by the Spring documentation if you waht to format to String and vice versa. So the Barry's UserIdConverter class is going to look like this:
public class UserIdConverter implements Formatter<User> {
private final UserDao userDao;
#Autowired
public UserIdConverter(UserDao userDao) {
this.userDao = userDao;
}
#Override
public User parse(String userId, Locale locale) {
return userDao.load(userId);
}
#Override
public String print(User target, Locale locale) {
return target.getUserId();
}
}
To register this Formatter you should include this in your XML config:
...
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" >
<property name="formatters">
<set>
<bean class="com.x.UserIdConverter"/>
</set>
</property>
</bean>
...
! NOTE that this class can be used only for formatting from some type T to String and vice versa. You can not format from type T to some other type T1 for example. If you have this case you should go with the Spring GenericConverter and use the Barry Pitman answer:
public abstract class AbstractTwoWayConverter<S, T> implements GenericConverter {
private Class<S> classOfS;
private Class<T> classOfT;
protected AbstractTwoWayConverter() {
Type typeA = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
Type typeB = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
this.classOfS = (Class) typeA;
this.classOfT = (Class) typeB;
}
public Set<ConvertiblePair> getConvertibleTypes() {
Set<ConvertiblePair> convertiblePairs = new HashSet<ConvertiblePair>();
convertiblePairs.add(new ConvertiblePair(classOfS, classOfT));
convertiblePairs.add(new ConvertiblePair(classOfT, classOfS));
return convertiblePairs;
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (classOfS.equals(sourceType.getType())) {
return this.convert((S) source);
} else {
return this.convertBack((T) source);
}
}
protected abstract T convert(S source);
protected abstract S convertBack(T target);
}
/**
* converter to convert between a userId and user.
* this class can be registered like so:
* conversionService.addConverter(new UserIdConverter (userDao));
*/
public class UserIdConverter extends AbstractTwoWayConverter<String, User> {
private final UserDao userDao;
#Autowired
public UserIdConverter(UserDao userDao) {
this.userDao = userDao;
}
#Override
protected User convert(String userId) {
return userDao.load(userId);
}
#Override
protected String convertBack(User target) {
return target.getUserId();
}
}
And add to your XML config:
...
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean" >
<property name="converters">
<set>
<bean class="com.x.y.UserIdConverter"/>
</set>
</property>
</bean>
...

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.

Categories

Resources