我试图使用MyBatis对某些调用DB进行调整,但到目前为止,我已经碰壁了。
我们说我有这个实体和地图制作者:
public interface Entity {
<T extends Entity> Class<Insertable<T>> mapper();
}
public interface Insertable<T extends Entity> {
void insert(T entity);
}
public interface ClientMapper extends Insertable<Client> {
void insert(Client client);
}
public interface CampaignMapper extends Insertable<Campaign> {
void insert(Campaign campaign);
}
public class Client implements Entity {
private final Long id;
public Client(final Long id) {
this.id = id;
}
@Override
public <T extends Entity> Class<Insertable<T>> mapper() {
return ClientMapper.class; // Incompatible types error
}
即使ClientMapper
的类型为Insertable<Client>
,Client
类型为Entity
,我也会收到此编译错误。
目标是获得以下类型安全的代码:
public class MapperOperation {
public static void insert(Entity entity) {
insert(entity, entity.mapper());
}
private static <V extends Entity, K extends Insertable<V>> void insert(V entity, Class<K> mapperClass) {
try (SqlSession session = PersistenceManager.get().openSession()) {
K mapper = session.getMapper(mapperClass);
mapper.insert(entity);
session.commit();
} catch (Exception e) {
log.error("Could not insert entity {}", entity, e);
}
}
}
这样,我可以使用任意insert
的实例调用方法Entity
,然后让他给我mapper
以便我可以插入它。
这可能吗?我做错了吗?
答案 0 :(得分:4)
应该使用这些更改进行编译:
public interface Entity {
<T extends Entity> Class<? extends Insertable<T>> mapper();
}
// ...
public <T extends Entity> Class<? extends Insertable<T>> mapper() {
return ClientMapper.class;
}
您无法将Class<ClientMapper>
分配给Class<Insertable<T>>
,原因与您无法将List<Integer>
分配给List<Number>
一样。
如果可以,那将是不安全的:
List<Integer> li = new ArrayList<>();
List<Number> ln = li; // does not compile
ln.add(3.14);
Integer i = li.get(0); // it's a Double!
编辑:这不是唯一的问题:该方法会返回依赖于T
的内容,但会返回另一个内容。问题可以简化:
class A {}
class B extends A {}
class C extends A {}
<T extends A> T getValue() {
return new C();
}
此处,T
可能已解析为A
的任何子类型,因此我们无法返回C
的实例,因为T
可能已解析为B
(例如,通过调用this.<B>getValue()
),C
不是B
的子类型。