RoboSpice сохраняют массив JSON с помощью OrmLite
Я использую RoboSpice с Spring для Android и хотел бы сохранить массив объектов JSON с OrmLite. GSON используется для сортировки JSON. С кэшированием по умолчанию все работает как положено. Но OrmLite, похоже, не нравится массив объектов.
Это упрощенная версия JSON:
[{"id": 1, "title": "Test 1"},{"id": 2, "title": "Test 3"},{"id": 3, "title": "Test 3"}]
Я хотел бы сохранить это в следующем объекте:
@DatabaseTable
public class Foo {
@DatabaseField(id = true)
private int id;
@DatabaseField
private String title;
// getters and setters
...
}
На основе примера RoboSpice OrmLite я создал следующий класс GsonSpringAndroidSpiceService для добавления OrmLite CacheManager. Это где проблема начинается.
public class CustomGsonSpringAndroidSpiceService extends GsonSpringAndroidSpiceService
{
@Override
public CacheManager createCacheManager(Application application)
{
// add persisted classes to class collection
List<Class<?>> classCollection = new ArrayList<Class<?>>();
classCollection.add(Foo.class);
// init
CacheManager cacheManager = new CacheManager();
cacheManager.addPersister(new InDatabaseObjectPersisterFactory(
application, new RoboSpiceDatabaseHelper(
application, "database.db", 1), classCollection));
return cacheManager;
}
}
Это приводит к следующей ошибке:
RequestProcessor.java:174(22356): java.lang.RuntimeException: Class [Lcom.example.model.Foo; is not handled by any registered factoryList
Когда я меняюсь classCollection.add(Foo.class);
в classCollection.add(Foo[].class);
Я получаю следующую ошибку:
RequestProcessor.java:174(22601): 14:42:23.112 pool-5-thread-1 An unexpected error occured when processsing request CachedSpiceRequest [requestCacheKey=foo, cacheDuration=-1, spiceRequest=com.example.app.FooRequest@4055df40]
RequestProcessor.java:174(22601): java.lang.IllegalArgumentException: No fields have a DatabaseField annotation in class [Lcom.example.app.model.Foo;
Кто-нибудь знает, как обрабатывать массив JSON с OrmLite CacheManager?
3 ответа
Я нашел способ обойти эту проблему. Я добавил дополнительный объект результата, который содержит массив объектов. Конечно, это возможно, только если вы можете манипулировать JSON. Все еще не очень доволен этим, потому что я ввел бесполезный класс для моей модели.
Так что мой JSON выглядит так:
{
"id": 1,
"result":[{"id": 1, "title": "Test 1"},{"id": 2, "title": "Test 3"},{"id": 3, "title": "Test 3"}]
}
И я добавил следующий класс для хранения результата JSON:
@DatabaseTable
public class FooResult {
@DatabaseField(id = true)
private int id;
@ForeignCollectionField(eager = false)
private Collection<Foo> result;
// getters and setters
...
}
Также добавлены внешние связи класса Foo:
@DatabaseTable
public class Foo {
@DatabaseField(id = true)
private int id;
@DatabaseField
private String title;
@DatabaseField(foreign = true)
private FooResult result;
// getters and setters
...
}
Я нашел способ, который работает для меня. Я не изменил свой JSON.
@DatabaseTable(tableName = SampleContract.Contributor.TABLE)
public class Contributor {
@DatabaseField(generatedId = true, columnName = SampleContract.Contributor._ID)
private int id;
@DatabaseField(columnName = SampleContract.Contributor.LOGIN)
public String login;
@DatabaseField(columnName = SampleContract.Contributor.CONTRIBUTIONS)
public int contributions;
@DatabaseField(foreign = true)
private ContributorsResult result;
@SuppressWarnings("serial")
@DatabaseTable(tableName = "contributor_list")
public static class ContributorsResult extends ArrayList<Contributor> {
@DatabaseField(id = true)
private int id = 0;
@ForeignCollectionField(eager = false)
private Collection<Contributor> result = this;
public Collection<Contributor> getResult() {
return result;
}
public void setResult(Collection<Contributor> result) {
if (result != null) {
this.clear();
this.addAll(result);
}
}
}
}
Я боролся с этим весь сегодняшний день и наконец понял, как сохранить массив JSON в базу данных SQLite, используя Robospice Spring Android без изменения JSON.
Это мой почтовый массив JSON, возвращенный с моего сервера:
[
{
"id": "5573547af58cd75df03306cc",
"name": "Simon",
"postheader": "First Post"
},
{
"id": "55735475f58cd75df03306cb",
"name": "Tyron",
"postheader": "Second Post"
}
]
Это похоже на JSON в этом вопросе:
[{"id": 1, "title": "Test 1"},{"id": 2, "title": "Test 3"},{"id": 3, "title": "Test 3"}]
Шаг 1:
Вам нужно будет создать 2 класса на стороне Android.
Одним из них будет обычный объект, который вы хотите сохранить из массива. В моем случае у меня есть объект "Post", и мой сервер возвращает массив "Post".
@DatabaseTable(tableName = "post")
@JsonIgnoreProperties(ignoreUnknown = true)
public class Post implements Serializable {
@DatabaseField(id = true)
private String id;
@DatabaseField
private String name;
@DatabaseField
private String postheader;
@DatabaseField(foreign = true,foreignAutoCreate = true,foreignAutoRefresh = true)
private EmbedPost posts;
Другой объект будет объектом-оберткой, который оборачивает массив, я назвал мой "EmbedPost".
@DatabaseTable
public class EmbedPost implements Serializable {
@DatabaseField(allowGeneratedIdInsert=true, generatedId=true)
private int ID;
@ForeignCollectionField(eager = false)
private Collection<Post> posts;
Определяя int с именем ID в моем классе EmbedPost, я эффективно создаю объект, который, если бы я преобразовал в JSON, выглядел бы так:
{"id": 1, "posts": [
{
"id": "5573547af58cd75df03306cc",
"name": "Simon",
"postheader": "First Post"
},
{
"id": "55735475f58cd75df03306cb",
"name": "Tyron",
"postheader": "Second Post"
}
]}
По сути, это строка JSON, которая очень похожа на ту, что использовал Уипко в своем решении.
{
"id": 1,
"result":[{"id": 1, "title": "Test 1"},{"id": 2, "title": "Test 3"},{"id": 3, "title": "Test 3"}]
}
Шаг 2:
Теперь вы сохраните его с помощью SpringAndroidSpiceService.
public class AndroidSpiceService extends SpringAndroidSpiceService {
private static final int WEBSERVICES_TIMEOUT = 10000;
@Override
public CacheManager createCacheManager( Application application ) {
CacheManager cacheManager = new CacheManager();
List< Class< ? >> classCollection = new ArrayList< Class< ? >>();
// add persisted classes to class collection
classCollection.add(EmbedPost.class);
classCollection.add( Post.class );
// init
RoboSpiceDatabaseHelper databaseHelper = new RoboSpiceDatabaseHelper( application, "sample_database.db", 3);
InDatabaseObjectPersisterFactory inDatabaseObjectPersisterFactory = new InDatabaseObjectPersisterFactory( application, databaseHelper, classCollection );
cacheManager.addPersister( inDatabaseObjectPersisterFactory );
return cacheManager;
}
@Override
public RestTemplate createRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
// set timeout for requests
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setReadTimeout( WEBSERVICES_TIMEOUT );
httpRequestFactory.setConnectTimeout( WEBSERVICES_TIMEOUT );
restTemplate.setRequestFactory( httpRequestFactory );
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
final List<HttpMessageConverter< ? >> listHttpMessageConverters = restTemplate.getMessageConverters();
listHttpMessageConverters.add( mappingJackson2HttpMessageConverter );
restTemplate.setMessageConverters( listHttpMessageConverters );
return restTemplate;
}
}
Обязательно добавьте и EmbedPost.class, и Post.class в ваш classCollection, так как ORMLite не сможет выполнить свою работу без сохранения обоих. Вы использовали ForeignKeys, когда писали свои объекты, и эти внешние ключи должны связываться с чем-то, поэтому оба класса должны сохраняться.
Если у вас возникли проблемы, попробуйте использовать logcat, чтобы выяснить это. Возможно, вам придется прочитать все сообщения, а не только сообщения об ошибках. Смотрите мой пост здесь, чтобы увидеть, как читать все сообщения LogCat:
Robospice хранит объект, который расширяет ArrayList в базе данных через Ormlite