2013-04-05 5 views
5

Android用のSpringでRoboSpiceを使用しています。OrmLiteでオブジェクトのJSON配列を永続化したいと考えています。 GSONはJSONマーシャリングに使用されます。デフォルトのキャッシュでは、すべてが期待通りに機能します。しかしOrmLiteはオブジェクトの配列が気に入らないようです。RoboSpiceはOrmLiteを使用したJSON配列を継承します

これは、JSONの簡易版である:

[{"id": 1, "title": "Test 1"},{"id": 2, "title": "Test 3"},{"id": 3, "title": "Test 3"}] 

私は、次のオブジェクトでこれを持続したいと思います:RoboSpice OrmLiteの例に基づいて

@DatabaseTable 
public class Foo { 
    @DatabaseField(id = true) 
    private int id; 
    @DatabaseField 
    private String title; 

    // getters and setters 
    ... 
} 

私は次のように作成しましたOrmLite CacheManagerを追加するGsonSpringAndroidSpiceServiceクラス。これが問題の始まりです。

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);私は次のエラーを取得 :JSON配列を処理するための方法を

RequestProcessor.java:174(22601): 14:42:23.112 pool-5-thread-1 An unexpected error occured when processsing request CachedSpiceRequest [requestCacheKey=foo, cacheDuration=-1, [email protected]] 
RequestProcessor.java:174(22601): java.lang.IllegalArgumentException: No fields have a DatabaseField annotation in class [Lcom.example.app.model.Foo; 

誰でもアイデアをOrmLite CacheManagerを使用していますか?

+0

は、私が紹介したくないhttp://stackoverflow.com/q/15801315/693752 – Snicolas

+0

@Snicolasの重複している可能性があり追加の結果クラス、回避策について私の答えを参照してください。 – Uipko

答えて

6

私はこの問題を回避する方法を見つけました。私はオブジェクトの配列を保持する余分な結果オブジェクトを追加しました。もちろんこれは、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 
    ... 
} 
+0

いいね、あなたの答えを受け入れる価値があります。それにもかかわらず、jsonを変更できない人には、リストをラップするために新しいクラスを導入する必要があります。 – Snicolas

+0

記録について:私はこの問題に苦労していました。私は 'private ForeignCollection result'を持っていましたが、それは機能しませんでした。 'ForeignCollection'を' Collection'に変更することで問題は解決しました。 – Nasir

+0

@Snicolas、私はjsonオブジェクトを変更する必要がない場合、解決策は何ですか? –

3

私は私のために働く方法を見つけました。私は私の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); 
      } 
     } 

    } 


} 
+0

ニース! JSONの出力をお願いしますか? – Guicara

+0

こちらをご覧ください。 https://api.github.com/repos/octo-online/robospice/contributors –

+1

完全な実例はこちらhttps://github.com/blandware/android-atleap –

0

私はこれで今日の全体を苦労し、最終的にJSONを変更することなく、Robospice春のAndroidを使用してSQLiteデータベースに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つのクラスを作成します。

1つは、アレイから保存する通常のオブジェクトです。私の場合は、 "Post"というオブジェクトがあり、私のサーバーは "Post"の配列を返します。

他のオブジェクトは、配列をラップするラッパーオブジェクトです。私は「EmbedPost」と呼ばれます。

{"id": 1, "posts": [ 
{ 
"id": "5573547af58cd75df03306cc", 
"name": "Simon", 
"postheader": "First Post" 
}, 
{ 
"id": "55735475f58cd75df03306cb", 
"name": "Tyron", 
"postheader": "Second Post" 
} 
]} 

これは、ことを効果的にJSON文字列です:int型を定義することにより

@DatabaseTable 
public class EmbedPost implements Serializable { 
    @DatabaseField(allowGeneratedIdInsert=true, generatedId=true) 
    private int ID; 
    @ForeignCollectionField(eager = false) 
    private Collection<Post> posts; 

は、私は効果的に私がJSONに変換する場合は、このようになりますことを、オブジェクトを作成しています、私のEmbedPostクラスでIDと呼ばれますUipkoが彼のソリューションで使用したのと非常によく似ています。

{ 
    "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; 
    } 

} 

ORMLiteあなたは両方を持続させずにその作業を行うことができないようごclassCollectionにEmbedPost.classとPost.classの両方を追加してください。あなたはあなたのオブジェクトを書き上げるときにForeignKeysを使用していました。これらの外部キーは何かに結びついているので、両方のクラスが持続しなければなりません。

問題が発生した場合は、logcatを使用して解決してください。エラーだけでなくすべてのメッセージを読む必要があるかもしれません。 すべてlogcatメッセージを読む方法を見るためにここに私のポストを参照してください:

Robospice storing object that extends ArrayList in database via Ormlite

関連する問題