I would like to implement the interface at runtime based on variable.
Example :
Class A implements interface1 {
public getValue() {}
}
Class B implements interface1 {
public getValue() {}
}
So I would like to have variable sitting in configuration..., for example ClasstoImplement=A
So, if ClasstoImplement=A, then I need to call Class A.getValue()
If ClasstoImplement=B, then I need to call Class B.getValue() at runtime. And I should be able to change value of ClasstoImplement at runtime.
My application is Spring based and runs in Tomcat.
Can someone please help me to find out if there is any way??
There are many possible solutions. The one of them is to use org.springframework.aop.target.HotSwappableTargetSource.
take a look at implementation that could be considered:
public class CustomSwappable<T> implements Interface1 {
private HotSwappableTargetSource targetSource;
private String key;
private Map<String, T> swappableBeans;
#PostConstruct
private void init() {
targetSource = new HotSwappableTargetSource(swappableBeans.values().iterator().next()); // first is the default
}
// you need to track changes in config and call this method if any modifications were done
public void configChanged(String key, String value) {
if (!this.key.equals(key)) {
return;
}
if (!swappableBeans.containsKey(value)) {
return;
}
targetSource.swap(swappableBeans.get(value));
}
#Override
public String getValue() {
return ((Interface1)targetSource.getTarget()).execute();
}
#Required
public void setConfigurationKey(String key) {
this.key = key;
}
#Required
public void setSwappableBeans(Map<String, T> swappableBeans) {
this.swappableBeans = swappableBeans;
}
}
and bean declaration should as follows:
<bean id="Interface1Swappable" class="path.to.CustomSwappable">
<property name="configurationKey" value="swappableKey"/>
<property name="swappableBeans">
<util:map value-type="path.toInterface1">
<!-- first is default -->
<entry key="classA">
<bean class="path.to.class.A"/>
</entry>
<entry key="classB">
<bean class="path.to.class.B"/>
</entry>
</util:map>
</property>
</bean>
Related
with spring xml configuration, it is possible to define the following in app context xml to populate the status field in the TestEnum:
app context xml
<bean id="blue" class="com.example.demo.test.TestEnum" factory-method="valueOf">
<property name="status" value="${testnum.blue.status}"/>
<constructor-arg>
<value>BLUE</value>
</constructor-arg>
</bean>
<bean id="red" class="com.example.demo.test.TestEnum" factory-method="valueOf">
<property name="status" value="${testnum.red.status}"/>
<constructor-arg>
<value>RED</value>
</constructor-arg>
</bean>
enum class
public enum TestEnum {
BLUE,
RED;
private String status;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
mystatus.properties
testnum.blue.status=good
testnum.red.status=bad
Is this possible with spring boot using application.properties + java configuration without xml?
Yes, a simple environment configuration class (annotated with #ConfigurationProperties for example), will map and do the conversion of your enum automatically.
Example:
#Configuration
#Validated
#ConfigurationProperties(prefix = "my.property.path")
public class TestConfiguration{
public enum TestEnum {
BLUE, RED
}
#NotNull
private TestEnum type;
public TestConfiguration() {
}
public #NotNull TestEnum getType() {
return this.type;
}
public void setType(#NotNull TestEnum type) {
this.type = type;
}
}
To test the setter dependency injection with an Array of string, I wrote the below-given code -
Pojo class is -
package com.abhishek.ioc.array;
public class Person {
private int id;
private String name;
private String[] hobbies;
public void showHobbies() {
System.out.println("Person name is - "+name+", id is - "+id);
for (int i = 0; i < hobbies.length; i++) {
System.out.println(hobbies[i]);
}
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setHobbies(String[] hobbies) {
this.hobbies = hobbies;
}
}
spring.xml file is -
<beans>
<bean id="person" class="com.abhishek.ioc.array.Person">
<property name="id" value="1"></property>
<property name="name" value="Abhisshek"></property>
<property name="hobbies">
<set>
<value>Playing cricket</value>
<value>Coding</value>
<value>Reading books</value>
</set>
</property>
</bean>
</beans>
Client code is -
package com.abhishek.ioc.array;
public class Client {
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("resources/spring.xml");
System.out.println("Creating Person object");
Person person = (Person)applicationContext.getBean("person");
System.out.println("Person object created");
person.showHobbies();
}
}
In spring.xml file, I tried tags <array>, <list> and <set> to inject data in array and all three tags are giving the correct result. How?
I am new to spring. I want to write a bean definition for the code below.
package com.abc.common.filter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;
public class RegexFilter implements Filter<String> {
Logger logger = Logger.getLogger(RegexFilter.class);
private Pattern regex;
private String lastMatch;
public RegexFilter(String regexString) {
this.lastMatch = null;
regex = Pattern.compile(regexString, Pattern.UNICODE_CHARACTER_CLASS);
}
#Override
public boolean matches(String text) {
text = text.toLowerCase();
if (text == null) {
logger.error("No text set for matching!");
return false;
}
Matcher matcher = regex.matcher(text);
if (matcher.find(0)) {// always start at index 0
this.lastMatch = matcher.group();
if (logger.isDebugEnabled()) {
logger.debug(matcher.group() + " found!");
}
return true;
}
return false;
}
public String getLastMatch(){
return this.lastMatch;
}
}
I am stuck after this line, i dont know how to include index or name? A little more clarification on index and values would be more than helpful.
<bean id="regexfilter" class="com.abc.common.filter.RegexFilter" />
<constructor-arg name="regexString" />
</bean>
You can define your bean
<bean id="regexfilter" class="com.abc.common.filter.RegexFilter" />
<constructor-arg type="java.lang.String" value="valueforregexstring"/>
</bean>
You can see more about bean definitions here
http://www.tutorialspoint.com/spring/constructor_based_dependency_injection.htm
in annotation based manor with pure java you can do something like this:
#Configuration
public class ApplicationConfig {
#Bean
public Filter regexFilter() {
return new RegexFilter("value_for_the_regex_filter");
}
}
or simply:
#Service
public class RegexFilter implements Filter<String> {
...
}
I am working on Spring auto wiring using spring configuration file(xml configuration). I want to inject beans based on a condition.
Let me go into details.
There are two classes 'EmailSender' and 'SmsSender' which implement the interface IMessageSender. Beans are configured for both classes in the configurations file.
I have another class SenderUser which has a instance variable of type IMessageSender in it.
package org.pradeep.core;
public class SenderUser {
private String name;
private String Type;
private IMessageSender msg;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return Type;
}
public void setType(String type) {
Type = type;
}
public IMessageSender getMsg() {
return msg;
}
public void setMsg(IMessageSender msg) {
this.msg = msg;
}
}
I want to inject IMessageSender into bean of SenderUser based on the value of SenderUser.getType(). That means first SernderUser.type should be set and then based on it's value (if value is 'email' then bean with the name 'email' should be wired else bean with the name 'sms' should be wired.) msg should be wired.
Please help me resolve the issue.
I believe the best approach is to implement a BeanFactory for SenderUser. Take a look at this post for an idea.
Interfaces can't be injected, they aren't beans/instances.
you may use SPEL
<bean id="user" class="SenderUser" autowire="byType">
<property name="type" value="email"/>
<property name="msg" value="#{type != null && type == 'email' ? email : sms}"/>
</bean>
<bean id="email" class="EmailSender"/>
<bean id="sms" class="SmsSender"/>
I tried some new Spring features and I found out that #CachePut and #CacheEvict annotations has no effect. May be I do something wrong. Could you help me?
My applicationContext.xml.
<cache:annotation-driven />
<!--also tried this-->
<!--<ehcache:annotation-driven />-->
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheCacheManager"
p:cache-manager-ref="ehcache"/>
<bean id="ehcache"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:config-location="classpath:ehcache.xml"/>
This part works well.
#Cacheable(value = "finders")
public Finder getFinder(String code)
{
return getFinderFromDB(code);
}
#CacheEvict(value = "finders", allEntries = true)
public void clearCache()
{
}
But if I want remove single value from cache or override it I can't do that. What I tested:
#CacheEvict(value = "finders", key = "#finder.code")
public boolean updateFinder(Finder finder, boolean nullValuesAllowed)
{
// ...
}
/////////////
#CacheEvict(value = "finders")
public void clearCache(String code)
{
}
/////////////
#CachePut(value = "finders", key = "#finder.code")
public Finder updateFinder(Finder finder, boolean nullValuesAllowed)
{
// gets newFinder that is different
return newFinder;
}
I found the reason why it didn't work. I called this methods from other method in the same class. So this calls didn't get through Proxy object therefore the annotations didn't work.
Correct example:
#Service
#Transactional
public class MyClass {
#CachePut(value = "finders", key = "#finder.code")
public Finder updateFinder(Finder finder, boolean nullValuesAllowed)
{
// gets newFinder
return newFinder;
}
}
and
#Component
public class SomeOtherClass {
#Autowired
private MyClass myClass;
public void updateFinderTest() {
Finder finderWithNewName = new Finder();
finderWithNewName.setCode("abc");
finderWithNewName.setName("123");
myClass.updateFinder(finderWithNewName, false);
}
}