Reputation: 5735
I am struggling to make this work:
public abstract class MapperFactory<M extends TaskMapper<? extends Message, ? extends Message, ? extends TaskForm>> {
public static <M extends TaskMapper<? extends Message, ? extends Message, ? extends TaskForm>> MapperFactory<M> getMapperFactory(Message msgIn, Message msgOut) {
if (msgIn.isMyMapper())
return new MyTaskMapperFactory();
throw new IllegalStateException("Mapper not found!");
}
public abstract TaskMapper<? extends Message, ? extends Message, ? extends TaskForm> getTaskMapper();
public static class MyTaskMapperFactory extends MapperFactory<MyTaskMapper> {
@Override
public TaskMapper<? extends Message, ? extends Message, ? extends TaskForm> getTaskMapper() {
return new MyTaskMapper();
}
}
}
public interface TaskMapper<I extends Message, O extends Message, F extends TaskForm> {
public F fillForm(I msgIn, O msgOut, F taskForm);
public O fillMsgOut(F taskForm);
}
public class MyTaskMapper implements TaskMapper<IncomingMessage, OutgoingMessage, MyTaskForm > {
public MyTaskForm fillForm(IncomingMessage msgIn, OutgoingMessage msgOut,
MyTaskForm taskForm) {
return null;
}
public OutgoingMessage fillMsgOut(MyTaskForm taskForm) {
return null;
}
}
The problem is a compilation error:
Type mismatch: cannot convert from MapperFactory.MyTaskMapperFactory to MapperFactory
in my MapperFactory here:
if (msgIn.isMyMapper())
return new MyTaskMapperFactory();
Any ideas how to fix this error?
Of course replacing:
public static <M extends TaskMapper<? extends Message, ? extends Message, ? extends TaskForm>> MapperFactory<M> getMapperFactory(Message msgIn, Message msgOut) {
if (msgIn.isMyMapper())
return new MyTaskMapperFactory();
throw new IllegalStateException("Mapper not found!");
}
with:
public static MapperFactory<?> getMapperFactory(Message msgIn, Message msgOut) {
if (msgIn.isMyMapper())
return new MyTaskMapperFactory();
throw new IllegalStateException("Mapper not found!");
}
would work, but that is not the answer that I am looking for.
This seems to be a problem with generic abstract factory pattern in general. Answers providing source samples using custom made-up objects are also welcomed.
Upvotes: 5
Views: 1294
Reputation: 39960
My solution would be killing as much of the generics as possible with a fire:
abstract class MapperFactory<M extends TaskMapper<?, ?, ?>> {
public static MapperFactory<?> getMapperFactory(Message msgIn, Message msgOut) {
if (msgIn.isMyMapper()) return new MyTaskMapperFactory();
throw new IllegalStateException("Mapper not found!");
}
public abstract M getTaskMapper();
}
class MyTaskMapperFactory extends MapperFactory<MyTaskMapper> {
@Override
public MyTaskMapper getTaskMapper() {
return new MyTaskMapper();
}
}
interface TaskMapper<I extends Message, O extends Message, F extends TaskForm> {
public F fillForm(I msgIn, O msgOut, F taskForm);
public O fillMsgOut(F taskForm);
}
class MyTaskMapper implements TaskMapper<IncomingMessage, OutgoingMessage, MyTaskForm> {
public MyTaskForm fillForm(IncomingMessage msgIn, OutgoingMessage msgOut, MyTaskForm taskForm) {
return null;
}
public OutgoingMessage fillMsgOut(MyTaskForm taskForm) {
return null;
}
}
It's really not necessary to repeat the type parameters of a class in every method that uses it if you don't really care what they are or don't need to constrain them more than the class signature does.
Upvotes: 1
Reputation: 1398
According to Effective Java, 2nd edition, item 28:
If a type parameter appears only once in a method declaration, replace it with a wildcard.
Your getMapperFactory method only uses the type parameter M in the return type. Following this advice gives the following method signature, and the method compiles:
public static MapperFactory<? extends TaskMapper<Message, ? extends Message, ? extends String>> getMapperFactory(Message msgIn, Message msgOut)
EDIT: The more I look at the code, the more I think MapperFactory shouldn't be parameterized. The parameter isn't used in the code here, getTaskMapper returns a TaskMapper.
Upvotes: 4
Reputation: 50041
The return statement works fine with a typecast:
return (BpmMapperFactory<MAPPER>)new Bpm007PrepareDocTaskMapperFactory();
That code will never execute though in its current form, because Bpm007PrepareDocTaskMapper doesn't extend BpmCommonMessageDto, so msgIn cannot possibly be an instance of Bpm007PrepareDocTaskMapper.
Upvotes: 1