我有一个与数据存储区交互的实用程序类(在我的情况下是GAE的内置数据存储区),它有以下方法:
//Class GaeDataUtil
public static <T> Optional<Key<T>> saveEntity(T entity)
(Optional
来自Guava图书馆,Key<T>
来自Objectify,尽管我怀疑其中任何一个都有所不同。)
我希望我的(最小)实体层次结构具有.save()
方法。因此:
public class User extends RootEntity
RootEntity
提供的地方:
public Optional<Key<T>> save() {
//Skipping the error-handling.
return GaeDataUtil.saveEntity(this);
}
我可以写:
User myUser = new User();
// set some properties
Optional<Key<User>> optKey = myUser.save();
但当然这不起作用,因为对myUser.save()
的调用会根据需要返回Optional<Key<RootEntity>>
而不是Optional<Key<User>>
。
我可以通过在User.save()
(以及Account.save()
和Project.save()
等等)中进行类型转换来避免此问题并抑制警告,但即使只有(例如)10个实体类扩展RootEntity
,这仍然是一些样板代码,只需将写入类型转换。此外,我认为如果我必须为每个派生类编写代码(尽管很小),那么拥有类层次结构的许多好处都会丢失(也会有其他类似的方法)。
有更好的解决方案吗?
使用Java 7更新。
答案 0 :(得分:2)
您只需要在T
方法中将其强制转换为通用类型RootEntity.save()
。
public <T> Optional<Key<T>> save() {
//Skipping the error-handling.
return (Optional<Key<T>> GaeDataUtil.saveEntity(this); // This line will generate a warning.
}
然后当你写作时,
Optional<Key<User>> optKey = myUser.save();
由于Target Type Inference,它会自动正确推断。
答案 1 :(得分:1)
一种解决方案是参数化RootEntity
这样的事情:
class RootEntity<Subclass extends RootEntity> {
public Optional<Key<Subclass>> save() {...}
}
然后定义您的子类,如:
class User extends RootEntity<User> {...}
之前我使用过这种模式。如果有一个更光滑的解决方案,我会渴望看到它。 :)
答案 2 :(得分:1)
这是最终奏效的:
createStore
通过两个步骤执行此操作(获取public <T extends RootEntity> Optional<Key<T>> save1() {
@SuppressWarnings("unchecked")
Key<T> key = (Key<T>) ofy().save().entity(this).now();
return Optional.fromNullable(key);
}
,然后将其打包在Key
)---它让目标类型推断正常工作。只需一步即可完成:
Optional
@Codebender建议的第二种形式显示错误(public <T extends RootEntity> Optional<Key<T>> save2() {
return (Optional<Key<T>>) Optional.fromNullable(ofy().save().entity(this).now());
}
),而不是Eclipse中的警告。
然而,@ Codelder使用目标类型推断的基本想法是合理的。