Objectify,Key <t>有可能吗?解决方法?</t>

时间:2013-10-27 07:21:55

标签: java generics reflection objectify type-erasure

我的意思是类型可以让我做以下事情。

public class AnyObject{

    List<this.type> list;   

}

我知道以下情况不会起作用。

public class AnyObject{

    List<this.getClass()> list;   

}

那么我如何创建一个让我们说一个列表,例如,这个的类型呢?

---------------更新---------------

我道歉我不认为我很清楚。我似乎得到了没有办法逃避类型擦除,但如果仍然有解决我的问题,我会更好地解释它。 披露,这更像是一个客观化的问题。 对不起,我现在就来看看。

我们走了,尽可能清楚......

对于我计划持久化的每个实体,在使用Objectiy的GAE数据存储中,我想有一个方法来使用id和parent字段生成Objectify Key<?>。让我们调用这个方法generateKey()。这是它的样子。

public Key<MyEntity> generateKey() {      
    Key<MyEntity> key = Key.create(this.parent, MyEntity.class, this.id);
    return key;
}

问题是我必须为我创建的每个实体或多或少地编写这个确切的代码。实际上,还有其他重复的代码,但我的观点可以单独使用这段重复的代码。

所以我尝试了这个。我创建了一个名为MyProjectEntity的类,让我所有的实体扩展它。然后使用泛型实现了generateKey()方法。

public abstract class MyProjectEntity<T, Y> {

    @Id     Long id;
    @Parent Key<T> parentKey;

    public Key<Y> generateKey() {
        Key<Y> key = Key.create(this.parentKey, this.getClass(), this.id);
        return key;
    }          

}

然后我用我创建的名为MyProjectEntity的新类扩展了所有实体类。像这样...

@Entity
public class MyEntity extends MyProjectEntity<MyEntityParent> {...}

听起来不错,现在我所有的实体都会有一个generateKey()方法,这个方法不太合适。 Objectify对我大吼大叫并说IllegalArgumentException,不能声明类型为T的Key。

然后我尝试Key<Object>,Objectify仍然不高兴,Objectify说Object不是注册实体。我应该注册对象!?!?而且有点失去Objectify提供的键入键的全部意义。

是否有一个好的解决方案。谢谢!

- 更新2 -

因为有人指出Key.create(myEntity)我应该指出我的全部用途......

/**********************************************************************************************************************
 * Constructors END & Identification and Relationship Methods BEGIN
 **********************************************************************************************************************/

    @ApiSerializationProperty(name = "id")
    public String getWebSafeKey() {

        String webSafeKey = getKey().getString();

        return webSafeKey;

    }

    public void setWebSafeKey(String webSafeKey) throws BadRequestException {

        try {
            Key<MyEntity> key = Key.create(webSafeKey);
            setKey(key);

        } catch (IllegalArgumentException illegalArgumentException) {
            throw new BadRequestException(ErrorMessage.INVALID_ID);
        }

    }

    @ApiSerializationProperty(name = "parentId")
    public String getParentWebSafeKey() {
        String webSafeKey = parent.getString();
        return webSafeKey;
    }

    public void setParentWebSafeKey(String parentWebSafeKey) throws BadRequestException {

        if (id == null) {
            try {
                parent = Key.create(parentWebSafeKey);
            } catch (IllegalArgumentException illegalArgumentException) {
                throw new BadRequestException(ErrorMessage.invalidParentId("Property"));
            }

        } else {
            /* Do nothing. Only set parent here if setWebSafeKey is never called, such as during a create. */
        }

    }

    @ApiSerializationProperty(ignored = AnnotationBoolean.TRUE)
    public Key<MyEntity> getParentKey() {
        return parent;
    }

    public void setParentKey(Key<MyEntity> parentKey) {
        this.parent = parentKey;
    }

    @ApiSerializationProperty(ignored = AnnotationBoolean.TRUE)
    public Key<MyEntity> getKey() {

        Key<MyEntity> key = Key.create(parent, MyEntity.class, id);

        return key;

    }

    public void setKey(Key<MyEntity> key) {
        id = key.getId();
        parent = key.getParent();
    }

    public boolean webSafeKeyEquals(String webSafeKey) {

        boolean equals;

        if (id !=null & parent !=null) {
            equals = getWebSafeKey().equals(webSafeKey);
        } else {
            equals = false;
        }

        return equals;

    }

/**********************************************************************************************************************
 * Identification Methods END & Other Getters and Setters BEGIN
 **********************************************************************************************************************/

所有这些都必须为我创建的每个实体插入,并将MyEntity替换为实际的实体名称。这不只是打字。此代码不属于实体类,而是属于某个抽象父代。如果我只能拥有该类中特定实体的唯一代码,那么我的模型将更清晰,更易于扩展。再次感谢。

5 个答案:

答案 0 :(得分:3)

这没有意义。考虑一下:你永远不会知道list的类型是什么。假设在某个类的某个方法中使用listthis可能始终是子类的实例。因此,List类型中list的参数永远不能在任何代码中假设。如果它永远不会被人知道,那又有什么意义呢?您只需使用List<?>

泛型是纯粹的编译时间。因此,依赖某些东西的运行时类是没有意义的。

我建议你有

public class AnyObject<T> {
    List<T> list;
}
例如,

和任何希望Foo成为list的班级List<Foo>应该只是从AnyObject<Foo>实施或继承。

答案 1 :(得分:3)

这没有意义List<this.getClass()> list;因为类型参数是java中的编译时间事物。此信息在运行时为erased

答案 2 :(得分:1)

不熟悉Objectify,只是泛型,我看到的是Key.create本身应该为返回的Key类型采用泛型参数<T>。因此,当您在超类中调用方法时,您应该执行以下操作:

Key<Y> key = Key.<Y>create(this.parentKey, this.getClass(), this.id);

您可能只需要这样做就可以解决错误(无论如何都应该这样做)。否则Key.create将尝试实例化一个新的Key<Y>,虽然当一个方法请求一个时,或多或少没有声明一个类型参数,显然Key.create可能不喜欢它。

我认为你还应该再看看你的Ts和Ys,因为看起来你正在混合它们。现在你将Key.create作为参数交给Key<T>但想要返回Key<Y>。此外,如果您将自己的类声明为<T, Y>,则仅使用<MyEntityParent>扩展该类是非法的。

查看您的代码我认为您要做的是创建与您调用它的方法相同的类的Key。 MyEntity中的IE类generateKey应返回Key<MyEntity>。我认为这样做的正确方法就是这样(这是有效的):

public abstract class MyProjectEntity<T, K> {
    Long id;
    Key<K> parentKey;

    public Key<K> generateKey() {
        return Key.<K>create(parentKey, this.getClass(), id);
    }
}

public class MyEntity extends MyEntityParent<MyEntityParent, MyEntity> {
    /*
     * K is now MyEntity and parentKey is a Key<MyEntity>
     * generateKey now does the following:
     *
     * public Key<MyEntity> generateKey() {
     *     return Key.<MyEntity>create(parentKey, MyEntity.class, id);
     * }
     *
     */
}

看起来你的例子不起作用就是给出错误,因为你没有正确地声明这些类型。但很难分辨,因为不清楚你的T和Y应该是什么。您只显示其中一个被声明的类型,至少在您的generateKey方法中,您正在处理Key.create Key<T>但想要返回Key<Y>

或许您应该在Objectify API中查看Registering Entities。 IE似乎你应该做这样的事情,这可能是你得到错误的原因:

static {
    ObjectifyService.register(MyEntityParent.class);
}

但无论如何,在Java泛型的世界里,除非发生其他事情,否则你真的应该能够在没有任何体操的情况下做这样的事情。擦除的本质是你无法在运行时找到类型,但类型基本上是“已知的”,因为T的所有实例都被参数类型替换。

public abstract class MyProjectEntity<T> {
    Key<T> parentKey;
}

变为

public class MyEntity extends MyProjectEntity<MyEntityParent> {
    Key<MyEntityParent> parentKey;
}

您无法确定parentKey是否为<MyEntityParent>类型,但该类型。您可以使用类似java.util.List的内容看到这一点,如果您执行以下操作:

List<Double> doubleList = new ArrayList<Double>(0);
doubleList.add("a string");

如果忽略编译器错误并尝试运行程序,您将得到以下内容:

Uncompilable source code - Erroneous sym type: java.util.ArrayList.add
java.lang.RuntimeException: Uncompilable source code - Erroneous sym type: java.util.ArrayList.add

因为列表 “只保存”Double的实例。这种情况可以与一个匿名类进行比较,其中ArrayList的add方法的实例现在正式将Double作为参数。它是无法编译的,因为我只是试图这样做:

public void add(Double element) {
    // add the element to the array
}

list.add("a string");

这显然是非法的。这个ArrayList的底层数组仍然是一个Object [],但是这些方法将被改变以反映类型并安全地确保数组在运行时只保存Double元素。

所以我建议你看看我提到的事情,因为除非你省略了相关的代码,否则看起来不止一个问题。

答案 3 :(得分:0)

我想我理解你的问题,这就是你如何做到的。诀窍是将子类作为父类的通用参数传递:

class Parent<T> {
    T doStuff() {
        T res = null;
        // res = ..... this.getClass() is ok...
        return res;
    }
}

public class SelfGerenic extends Parent<SelfGerenic> {
}

public class OtherSubClass extends Parent<OtherSubClass> {
}

答案 4 :(得分:0)

如果我找对你,你正在寻找这样的东西:

public class Test {
private int id;

public Key<Test> getKey() {
    return createKey(id, this.getClass());
}

public static <T> Key<T> createKey(int id, Class<? extends T> clazz) {
    return new Key<T>(clazz, id);
}

private static class Key<T> {
    private final Class<? extends T> clazz;
    private final int id;

    private Key(Class<? extends T> clazz, int id) {
        this.clazz = clazz;
        this.id = id;
    }

    private int getId() {
        return id;
    }

    private Class<? extends T> getClazz() {
        return clazz;
    }
}

public int getId() {
    return id;
}
}

此处无法替换 Test public Key<Test> getKey() {! 这是因为getKey()总是返回Key。它无法返回Test。 所以基本上没有,没有办法改变这种行为。此外,没有办法获得“当前”类的泛型类型。这是java泛型的某种限制:P

您可以在此处删除泛型,因此您不必每次都实现getKey()。

public class Test {
private int id;

public Key getKey() {
    return createKey(id, this.getClass());
}

public static  Key createKey(int id, Class clazz) {
    return new Key(clazz, id);
}

private static class Key {
    private final Class clazz;
    private final int id;

    private Key(Class clazz, int id) {
        this.clazz = clazz;
        this.id = id;
    }

    private int getId() {
        return id;
    }

    private Class getClazz() {
        return clazz;
    }
}

public int getId() {
    return id;
}
}