我有一个带有2个静态嵌套类的类,它们对2种不同的泛型类型执行相同的操作。
我像往常一样将这两个类公开为bean,并为构造函数添加了@Autowired。
这是基本设置
abstract class <T> Parent implements MyInterface<T> {
private final Service service;
Parent(Service service){ this.service = service; }
@Override public final void doInterfaceThing(T thing){
T correctedT = map(thing);
service.doTheThing(correctedT);
}
protected abstract T map(T t);
@Service
public static class ImplA extends Parent<A> {
@Autowired ImplA (Service service){ super(service); }
A map(A a){ //map a }
}
@Service
public static class ImplB extends Parent<B> {
@Autowired ImplB (Service service){ super(service); }
B map(B b){ //map b }
}
}
在另一堂课中,我有
@Service
public class Doer {
private final List<MyInterface<A>> aImpls;
@Autowired public Doer(List<MyInterface<A>> aImpls){ this.aImpls = aImpls; }
public void doImportantThingWithA(A a){
aImpls.get(0).doInterfaceThing(a);
}
}
当我运行该应用程序时,所有内容似乎都已正确注入,并且当我在ImplA和ImplB构造函数中设置断点时,“ service”的值不为null。我在Doer的aImpls列表中也有一个ImplA bean。
但是,当我调用doImportantThingWithA(a)时,ImplA中的“服务”为空,显然我死了。
我不确定这怎么可能,因为:
之所以使用嵌套类,是因为这两个实现之间唯一发生变化的是map()函数。尝试避免使用1行变化代码的额外类。
更多信息: 当我在Parent.doInterfaceThing()中添加断点时,如果在“服务”上添加监视,则该值将为null。如果我添加一个getService()方法,然后调用getService()而不是直接引用this.service,我将获得正确的服务bean。我不知道这意味着什么,但是代理似乎有些奇怪。
答案 0 :(得分:1)
引起问题的原因似乎是Parent.doInterfaceThing();
如果我从方法签名中删除了final,则“ service”字段将正确填充,并且代码将按预期工作。
我根本不明白为什么更改方法签名会影响类中final字段的注入值...但是现在可以使用了。
答案 1 :(得分:0)
我对“使用映射器”评论的意思是这样的:
class MyInterfaceImpl implements MyInterface {
@Autowired
private final Service service;
@Override public final <T> void doInterfaceThing(T thing, UnaryOperator<T> mapper){
T correctedT = mapper.apply(thing);
service.doTheThing(correctedT);
}
// new interface to allow autowiring despite type erasure
public interface MapperA extends UnaryOperator<A> {
public A map(A toMap);
default A apply(A a){ map(a); }
}
@Component
static class AMapper implements MapperA {
public A map(A a) { // ... }
}
public interface MapperB extends UnaryOperator<B> {
public B map(B toMap);
default B apply(B b){ map(b); }
}
@Component
static class BMapper implements MapperB {
public B map(B a) { // ... }
}
}
这确实比原始行多了几行,但并不多。但是,您确实有更好的关注点分离。我确实想知道自动装配与泛型如何在您的代码中工作,看起来确实会引起问题。
您的客户看起来像这样:
@Service
public class Doer {
private final List<MapperA> aMappers;
private final MyInterface myInterface;
@Autowired public Doer(MyInterface if, List<MapperA> mappers){
this.myInterface = if;
this.aImpls = mappers; }
public void doImportantThingWithA(A a){
aMappers.stream().map(m -> m.map(a)).forEach(myInterface::doInterfaceThing);
}
}