接口

时间:2017-01-23 16:39:53

标签: java generics polymorphism mybatis

我试图使用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以便我可以插入它。

这可能吗?我做错了吗?

1 个答案:

答案 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的子类型。