У меня есть приложение Google App Engine + Java, которое успешно работает в течение многих лет (с использованием JDO + хранилище данных для постоянного хранения), и у меня не было проблем ( время от времени и неохотно ) обновление свойствасущность в консоли Google Datastore вручную.
Недавно (возможно, последние 2-3 месяца) я заметил изменение в поведении, которое нарушает наше приложение.Я не понимаю точно, что идет не так или как мы могли справиться с этим.
Итак, мой вопрос: почему он ведет себя по-разному и что я могу с этим поделать?
Позвольте мне сначала попытаться объяснить поведение, которое я наблюдаю, а затем показать мой наименьший возможный повторяющийся контрольный пример..
Предположим, у вас был простой класс персистентности:
@PersistenceCapable
public class Account implements Serializable {
@Persistent private ShortBlob testShortBlob;
@Persistent private String name;
// ...etc...
}
Если в прошлом я редактировал имя через веб-консоль Datastore, он работал бы, как и ожидалось, поле имени изменилось бы ивсе остальное будет работать нормально.
Сейчас я наблюдаю такое поведение: после сохранения сущности через консоль я больше не могу запрашивать и загружать сущность в JDO, я получаю:
java.lang.ClassCastException: com.google.appengine.api.datastore.Blob cannot be cast to com.google.appengine.api.datastore.ShortBlob
Что указывает на некоторое базовое изменение хранилища данных, которое означает, что поле ShortBlob меняет тип с ShortBlob на Blob (даже если я не изменяю это поле через консоль).
Этот тестовый пример будет копироватьпроблема:
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
// this one really is a ShortBlob - will load fine in JDO
Entity account = new Entity("Account", "123");
account.setProperty("name", "Test Name");
account.setUnindexedProperty("testShortBlob", new ShortBlob("blah".getBytes()));
datastore.put(account);
// this one really is not a ShortBlob, its a blob - it will fail for the same reason I am seeing in production.
account = new Entity("Account", "124");
account.setProperty("name", "Test Name 2");
account.setUnindexedProperty("testShortBlob", new Blob("blah".getBytes()));
datastore.put(account);
// then load the entity via JDO
try {
accountFromJdo = pm.getObjectById(Account.class, key);
} catch (Exception ex) {
System.out.println("We get here, the object won't load with the ClassCast Exception");
}
Так вот в чем проблема, но почему сохранение через консоль облачного хранилища данных заменяет ShortBlob на Blob?
Мой обходной путь в настоящее время заключается в том, чтобы установить для полей ShortBlob значение null в консоли хранилища данных, что позволит загружать объект.Но это отстой, если данные в BLOB-объекте важны!
Обновление:
Я проводил дополнительное тестирование, используя низкоуровневый JSON API, чтобы увидетьесли бы я мог увидеть разницу в необработанных ответах JSON до и после сохранения объекта через консоль.Хорошая новость в том, что я могу!
Перед редактированием сущности через консоль поле shortBlob, сохраненное в хранилище данных через интерфейс JDO App Engine, будет выглядеть так:
},
"testShortBlob": {
"blobValue": "tNp7MfsjhdfjkahsdvfkjhsdvfIItWyzy6glmIrow4WWhRPbhQ/U+MGX3opVvpxu"
},
Ноесли я зайду в консоль хранилища данных и отредактирую сущность (оставьте поле blob без изменений, отредактируйте несвязанное поле, например имя. Теперь, когда я запускаю тот же запрос, я получаю:
},
"testShortBlob": {
"blobValue": "tNp7MfsjhdfjkahsdvfkjhsdvfIItWyzy6glmIrow4WWhRPbhQ/U+MGX3opVvpxu",
"excludeFromIndexes": true
},
Незначительная разница, но я думаю, что это важно, согласно документы Java ShortBlob
проиндексированы, а Blob
нет.
Итак, я думаю, что мой вопрос сейчас таков: почему редактирование сущности через консоль Cloud Datastore изменяет индексированный статус полей BLOB-объектов?