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

时间:2019-11-26 10:57:32

标签: google-app-engine google-cloud-datastore objectify

我目前正在将项目的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

1 个答案:

答案 0 :(得分:0)

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

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

这尤其奇怪,因为旧的低级API将字符串写入Entity结构中;仅当字符串超过一定长度时才需要Text。因此,JDO应该处理String。您在String字段上是否有某种特殊的注释,以强制其期望Text?该堆栈跟踪是什么样的?

相关问题