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 {
}
Thi开发者_Python百科s 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...
Easy way: if possible, make your implementing class implement your union interface instead of the two separate interfaces.
Less clear way, but does not introduce addtional classes (needs generics):
public interface A { }
public interface B { }
public class C implements A, B { }
public class D {
private A a;
private B b;
public <T extends A & B> void setObject(T o) {
this.a = o;
this.b = o;
}
public static void main(String[] args) {
D d = new D();
d.setObject(new C());
}
}
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();
Yet another option with generics (mostly as a theoretical exercise), doesn't require duplicated fields, but requires a holder object:
class ReaderStreamHolder<T extends ItemReader & ItemStream> {
private final T target;
public ReaderStreamHolder(T target) {
this.target = target;
}
public T get() {
return target;
}
}
.
private ReaderStreamHolder<?> blah;
public <T extends ItemReader & ItemStream> void setItemReader(T target) {
this.blah = new ReaderStreamHolder<T>(target)
};
.
blah.get().close();
精彩评论