我目前正在将项目的DAO类从JDO实施迁移到Objectify V6。 我的要求是确保在回滚的情况下可以使用旧版本的DAO加载由Objectify保存的实体。
在旧代码中,字符串存储为Text
。并且,如果我在实体定义中保留Text
字段,Objectify会将其作为String
放入数据存储区(因为不再有Text
类型)。
当前的新DAO实现不向后兼容,因为JDO实现将String转换为Text类型时出现了ClassCastException
。
是否可以使用Objectify V6将文本类型存储到数据存储中?
我尝试在实体定义中使用String
而不是Text
并创建一个TranslatorFactory
进行转换,但是我找不到正确的数据存储区Value
实现类型。
public class StringTextTranslatorFactory implements TranslatorFactory<String, Text> {
@Override
public Translator<String, Text> create(TypeKey<String> tk, CreateContext ctx, Path path) {
return new Translator<String, Text>() {
@Override
public String load(Value<Text> node, LoadContext ctx, Path path) throws SkipException {
Text text = node.get();
return text != null ? text.getValue() : "";
}
@Override
public Value<Text> save(String pojo, boolean index, SaveContext ctx, Path path)
throws SkipException {
return ???;
}
};
}
}
更新
该项目正在为App Engine数据存储区使用JDO 2.3的实现。该实现基于DataNucleus访问平台的1.0版。
数据实体定义如下:
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class CrmNote {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id;
@Persistent
private Text note;
}
Stacktrace:
java.lang.ClassCastException: java.lang.String cannot be cast to com.google.appengine.api.datastore.Text
at com.timzon.snapabug.server.data.CrmNote.jdoReplaceField(CrmNote.java)
at com.timzon.snapabug.server.data.CrmNote.jdoReplaceFields(CrmNote.java)
at org.datanucleus.state.JDOStateManagerImpl.replaceFields(JDOStateManagerImpl.java:2772)
at org.datanucleus.state.JDOStateManagerImpl.replaceFields(JDOStateManagerImpl.java:2791)
at org.datanucleus.store.appengine.DatastorePersistenceHandler.fetchObject(DatastorePersistenceHandler.java:519)
at org.datanucleus.store.appengine.query.DatastoreQuery.entityToPojo(DatastoreQuery.java:649)
at org.datanucleus.store.appengine.query.DatastoreQuery.entityToPojo(DatastoreQuery.java:603)
at org.datanucleus.store.appengine.query.DatastoreQuery.access$300(DatastoreQuery.java:119)
at org.datanucleus.store.appengine.query.DatastoreQuery$6.apply(DatastoreQuery.java:783)
at org.datanucleus.store.appengine.query.DatastoreQuery$6.apply(DatastoreQuery.java:774)
at org.datanucleus.store.appengine.query.LazyResult.resolveNext(LazyResult.java:94)
at org.datanucleus.store.appengine.query.LazyResult.resolveAll(LazyResult.java:116)
at org.datanucleus.store.appengine.query.LazyResult.size(LazyResult.java:110)
at org.datanucleus.store.appengine.query.StreamingQueryResult.size(StreamingQueryResult.java:130)
at org.datanucleus.store.query.AbstractQueryResult.toArray(AbstractQueryResult.java:399)
at java.util.ArrayList.<init>(ArrayList.java:178)
at com.timzon.snapabug.server.dao.CrmNoteDAO.getOrderedCrmNotes(CrmNoteDAO.java:27)
在自动生成的jdoReplaceField
方法中发生异常,该方法由JDO编译后“增强”功能添加。我对增强型类进行了反编译,并且看到数据存储对象直接转换为Text
类型:
public void jdoReplaceField(int index) {
if (this.jdoStateManager == null) {
throw new IllegalStateException("state manager is null");
} else {
switch(index) {
case 0:
this.id = (Long)this.jdoStateManager.replacingObjectField(this, index);
break;
case 1:
this.note = (Text)this.jdoStateManager.replacingObjectField(this, index);
break;
default:
throw new IllegalArgumentException("out of field index :" + index);
}
}
}
因此,如果note
字段作为String
保存在数据存储中,则在回滚的情况下将抛出ClassCastException
。
答案 0 :(得分:0)
无法通过Objectify 6使用的Google提供的SDK明确存储Text
类型;只有StringValue
。 Text
甚至不在罐子里。
但是,我认为这并不重要。最终,两个SDK(旧的Appengine和新的SDK)都只是来回转换为protobuf结构。它们应该兼容。
这尤其奇怪,因为旧的低级API将字符串写入Entity
结构中;仅当字符串超过一定长度时才需要Text
。因此,JDO应该处理String
。您在String字段上是否有某种特殊的注释,以强制其期望Text
?该堆栈跟踪是什么样的?