Search code examples
javaspringproxydynamic-proxy

How to have a Spring dynamic proxy with 2 interfaces?


I have an object that is injected into my class by Spring (JdbcCursorItemReader if you care).

It implements 5 interfaces, two of which I care about (ItemReader, ItemStream). If I code my class to one or the other, the spring dynamic proxy gets properly injected and I can call methods on it

private ItemReader blah;
public void setItemReader( blah ) { this.blah = blah };

Cool, that works as expected. I can also cast it to an ItemStream if I want to do something based on the ItemStream Interface:

((ItemStream))blah.close();

Cool, that lets me access methods of both classes. However, I am not a fan of casting, and know where has to be a better Spring Magic way to do it. The way I thought of was to make an Interface that combines both:

public interface IStreamingItemReader<T> extends ItemReader<T>, ItemStream {
}

This lets my code use both... but the proxy injection predictably fails.

Failed to convert property value of type [$Proxy0 implementing org.springframework.beans.factory.InitializingBean,org.springframework.batch.item.ItemReader,org.springframework.batch.item.ItemStream,org.springframework.aop.scope.ScopedObject,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [blah.IStreamingItemReader] for property 'itemReader'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [$Proxy0 implementing org.springframework.beans.factory.InitializingBean,org.springframework.batch.item.ItemReader,org.springframework.batch.item.ItemStream,org.springframework.aop.scope.ScopedObject,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [blah.IStreamingItemReader] for property 'itemReader': no matching editors or conversion strategy found

The part that got my eye was no matching editors or conversion strategy found

Is there a way to teach Spring when it sees a JdbcCursorItemReader, to make a proxy of a IStreamingItemReader?

I realize I could fix this with CGLib and class based proxies... but if I could keep this as a dynamic interface proxy, I would be happier...


Solution

  • Option 1

    private ItemReader blah;
    private ItemStream blubb;
    public void setItemReader( blah ) { this.blah = blah };
    public void setItemStream( blubb ) { this.blubb = blubb };
    

    Option 2

    class ItemAccessor {
     private ItemReader reader;
     private ItemStream stream;
     // Setter & co ...
    }
    

    Then:

    private ItemAccessor accessor;
    
    accessor.getReader().read();
    accessor.getStream().stream();