Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring: Delegate to custom proxy wrapper for interface injection

In a very large legacy application I have interfaces and classes that do not implement those interfaces.

The interfaces are generated based on the class so the signatures are the same (except the interface adds another exception on top) and the names are similar (so it's easy to find the class name from the interface name).

To get an implementation of the interface we do a bunch of processing and logging calls but basically use java.lang.reflect.Proxy to delegate to the class. Simplified it looks like this:

// This will create a proxy and invoke handler that calls HelloWorld.doSomething
HelloWorldInterface i = MyProxyUtil.getInstance(HelloWorldInterface.class);
i.doSomething();

public interface HelloWorldInterface {
    public void doSomething() throws Exception;  
}

public class HelloWorld {
    public void doSomething() {
     //something
    }
}

Is it possible with Spring annotation processing, to generically @Autowire all fields of type *Interface and have spring use MyProxyUtil.getInstance(*Interface.class) to inject the implementation?

Such that

@Autowire HelloWorldInterface a;

HelloWorldInterface b = MyProxyUtil.getInstance(HelloWorldInterface.class);

@Autowire AnotherInterface c;

AnotherInterface d = MyProxyUtil.getInstance(AnotherInterface.class);


a == b
c == d
like image 497
case nelson Avatar asked Jul 16 '13 21:07

case nelson


1 Answers

Yes, you need to implement a AutowireCandidateResolver.

For example:

public class ProxyAutowiredCandidateResolver extends SimpleAutowireCandidateResolver {

    @Override
    public Object getSuggestedValue(DependencyDescriptor descriptor) {
        String dependencyClassName = descriptor.getDependencyType().getSimpleName();
        if (dependencyClassName.endsWith("Interface")) {
            return MyProxyUtil.getInstance(descriptor.getDependencyType());
        }

        return super.getSuggestedValue(descriptor);
    }

}

You could use a BeanFactoryPostProcessor to configure it in the application context:

public class AutowireCandidateResolverConfigurer implements BeanFactoryPostProcessor {

    private AutowireCandidateResolver autowireCandidateResolver;

    public void postProcessBeanFactory(
            ConfigurableListableBeanFactory beanFactory) throws BeansException {
        DefaultListableBeanFactory  bf = (DefaultListableBeanFactory) beanFactory;
        bf.setAutowireCandidateResolver(autowireCandidateResolver);


    }

    public AutowireCandidateResolver getAutowireCandidateResolver() {
        return autowireCandidateResolver;
    }

    public void setAutowireCandidateResolver(

            AutowireCandidateResolver autowireCandidateResolver) {
        this.autowireCandidateResolver = autowireCandidateResolver;
    }

}

<bean id="autowireCandidateResolverConfigurer" class="AutowireCandidateResolverConfigurer">
        <property name="autowireCandidateResolver">
            <bean class="ProxyAutowiredCandidateResolver" />
        </property>
</bean>
like image 194
Jose Luis Martin Avatar answered Sep 18 '22 19:09

Jose Luis Martin