Я бы использовал Пользовательские инъекции из Guice
для достижения этого.
Во-первых, я создам аннотацию для аннотации MyService, которую я хочу внедрить, основываясь на типе суперкласса.
@BindingAnnotation
@interface MyServiceInject {
}
Тогда я бы пометил свое поле MyService аннотацией.
static abstract class Base {
@MyServiceInject
protected MyService myService;
}
Теперь нам нужен пользовательский TypeListener
, который будет вызываться каждый раз, когда мы сталкиваемся с точкой инъекции.
Вот как мы его создадим.
static class ClassBasedMyServiceInjectionListener implements TypeListener {
@Override
public <I> void hear(TypeLiteral<I> typeLiteral, TypeEncounter<I> encounter) {
Class<?> clazz = typeLiteral.getRawType();
while (clazz != null) {
for (Field field : clazz.getDeclaredFields()) {
if (field.getType() == MyService.class && field.isAnnotationPresent(MyServiceInject.class)) { //if type of field is MyService and it has MyServiceInject annotation
encounter.register(new ClassBasedMyServiceInjector<>(field,
typeLiteral.getType(),
encounter.getProvider(MyServiceA.class),
encounter.getProvider(MyServiceB.class)
)
); //Now register a MemberInjector for this encounter.
}
}
clazz = clazz.getSuperclass();
}
}
}
Теперь нам нужен MemberInjector, который будет выглядеть следующим образом.
static class ClassBasedMyServiceInjector<T> implements MembersInjector<T> {
private final Field field;
private final Type superClassType;
private final Provider<MyServiceA> myServiceAProvider;
private final Provider<MyServiceB> myServiceBProvider;
ClassBasedMyServiceInjector(Field field, Type superClassType, Provider<MyServiceA> myServiceAProvider, Provider<MyServiceB> myServiceBProvider) {
this.field = field;
this.superClassType = superClassType;
this.myServiceAProvider = myServiceAProvider;
this.myServiceBProvider = myServiceBProvider;
field.setAccessible(true);
}
public void injectMembers(T t) { //this will be called when guice wants to inject members
try {
if (superClassType == A.class) {//if super class is of type A
field.set(t, myServiceAProvider.get()); //inject MyServiceA
} else if (superClassType == B.class) { //if super class is of type B
field.set(t, myServiceBProvider.get()); //inject MyServiceB
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
Наконец, я бы связал наш пользовательский TypeListener
в методе конфигурирования нашего модуля вот так.
@Override
protected void configure() {
bindListener(Matchers.any(), new ClassBasedMyServiceInjectionListener());
}
Надеюсь, это поможет.