0

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??

Tiny
  • 27,221
  • 105
  • 339
  • 599
Dev
  • 31
  • 1
  • 8
  • You could just inject both implementations into your class, and call the correct one based on reading an externally stored config parameter. – Mark Chorley Feb 19 '16 at 10:54

1 Answers1

0

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>
hahn
  • 3,588
  • 20
  • 31
  • Thanks for the information. I have 2 errors.. One is "SampleService" is giving error. And do we need to define "configChanged" in the interface also? – Dev Feb 19 '16 at 10:45
  • @Dev regarding the first issue, you should replace it with 'Interface1' instead of SampleService. 'configChanged' shouldn't be overridden, my mistake. Consider this code as demonstration sample. The actual implementation should be done depending on your needs. – hahn Feb 19 '16 at 10:50
  • Thanks. In runtime, how would I change the implementation from ClassA to ClassB. Please let me know... – Dev Feb 19 '16 at 11:02