使用 Objectify 6 将文本类型放入数据存储

Put Text type to datastore with Objectify 6

我目前正在将项目的 DAO classes 从 JDO 实现迁移到 Objectify V6。 我的要求是确保在回滚的情况下可以使用旧版本的 DAO 加载由 Objectify 保存的实体。

在旧代码中,字符串存储为 Text。如果我在实体定义中留下 Text 字段,Objectify 会将其作为 String 放入数据存储区(因为不再有 Text 类型)。

当前新的 DAO 实现不向后兼容,因为 ClassCastException 当 JDO 实现将 String 转换为 Text 类型时出现。

有没有办法使用 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;
}

堆栈跟踪:

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.access0(DatastoreQuery.java:119)
    at org.datanucleus.store.appengine.query.DatastoreQuery.apply(DatastoreQuery.java:783)
    at org.datanucleus.store.appengine.query.DatastoreQuery.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)

由 JDO post-编译 "enhancement" 添加的自动生成的 jdoReplaceField 方法中发生异常。我反编译了增强型 class,我看到数据存储对象直接转换为 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

无法使用 Objectify 6 使用的 Google 提供的 SDK 显式存储 Text 类型;只有 StringValueText 甚至不在罐子里。

不过,我认为这不重要。最终,两个 SDK(旧的应用引擎和新的)只是来回转换为 protobuf 结构。它们应该是兼容的。

特别奇怪,因为老低级API把字符串写进了Entity结构; Text 仅当字符串超过一定长度时才需要。所以JDO应该处理String。您的字符串字段上是否有某种特殊注释以强制它期望 Text?该堆栈跟踪是什么样的?