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

Другие вопросы по тегам