2013-04-05 3 views
5

Ich benutze RoboSpice mit Spring für Android und möchte ein JSON-Array von Objekten mit Ormlite persistieren. GSON wird für das JSON-Marshalling verwendet. Mit dem Standard-Caching funktioniert alles wie erwartet. Aber OrmLite scheint das Array von Objekten nicht zu mögen.RoboSpice persistent JSON-Array mit Ormlite

Dies ist eine vereinfachte Version des JSON:

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

ich dies in dem folgende Objekt bestehen bleiben möchte:

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

    // getters and setters 
    ... 
} 

Basierend auf dem RoboSpice OrmLite Beispiel ich folgende erstellt habe GsonSpringAndroidSpiceService-Klasse zum Hinzufügen des OrmLite CacheManagers. Hier beginnt das Problem.

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

Dies führt zu dem folgenden Fehler:

RequestProcessor.java:174(22356): java.lang.RuntimeException: Class [Lcom.example.model.Foo; is not handled by any registered factoryList 

Als ich classCollection.add(Foo.class);-classCollection.add(Foo[].class); bekomme ich folgende Fehler ändern:

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; 

jemand eine Idee wie ein JSON-Array zu handhaben mit dem OrmLite CacheManager?

+0

ein Duplikat http://stackoverflow.com/q/15801315/693752 – Snicolas

+0

@Snicolas sein Darf ich möchte nicht vorstellen Eine zusätzliche Ergebnisklasse finden Sie in meiner Antwort zur Problemumgehung. – Uipko

Antwort

6

Ich habe eine Arbeit um dieses Problem gefunden. Ich habe ein zusätzliches Ergebnisobjekt hinzugefügt, das das Array von Objekten enthält. Dies ist natürlich nur möglich, wenn Sie den JSON manipulieren können. Immer noch nicht wirklich glücklich damit, weil ich meinem Modell eine nutzlose Klasse eingeführt habe.

Also mein das JSON wie folgt aussieht:

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

Und fügte ich die folgende Klasse das JSON Ergebnis zu halten:

@DatabaseTable 
public class FooResult { 
    @DatabaseField(id = true) 
    private int id; 
    @ForeignCollectionField(eager = false) 
    private Collection<Foo> result; 

    // getters and setters 
    ... 
} 

Auch die ausländische Beziehung hinzugefügt die die Foo Klasse:

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

    // getters and setters 
    ... 
} 
+0

Schön, es wäre es wert, Ihre Antwort zu akzeptieren. Nichtsdestotrotz gibt es für Leute, die den JSON nicht ändern können, keine Alternative: Sie müssen eine neue Klasse einführen, um die Liste zu umhüllen. – Snicolas

+0

Für den Rekord: Ich hatte mit diesem Problem zu kämpfen und ich hatte 'private ForeignCollection Ergebnis 'und es hat nicht funktioniert. Durch Ändern der 'ForeignCollection' in' Collection' wurde das Problem behoben. – Nasir

+0

@Snicolas, was wäre die Lösung, wenn ich das JSON-Objekt nicht ändern muss? –

3

Ich habe den Weg gefunden, der für mich funktioniert. Ich habe meinen JSON nicht geändert.

@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

Schön! Können Sie uns bitte die Ausgabe Ihres JSON geben? – Guicara

+0

Sie können es hier finden. https://api.github.com/repos/octo-online/rospospice/contributors –

+1

Das voll funktionsfähige Beispiel finden Sie hier https://github.com/blandware/android-atleap –

0

ich mit diesem die ganze heute gekämpft und schließlich dachte wie ein JSON-Array in eine SQLite-Datenbank ohne Änderung der JSON mit Robospice Frühling Android zu speichern.

Dies ist mein Beitrag JSON-Array von meinem Server zurückgegeben:

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

: Schritt 1:

Sie müssen

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

Dies ist in dieser Frage an die JSON ähnlich Erstellen Sie 2 Klassen auf der Android-Seite.

Eines ist das normale Objekt, das Sie aus dem Array speichern möchten. In meinem Fall habe ich ein Objekt namens "Post" und mein Server gibt ein Array von "Post" zurück.

@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; 

Das andere Objekt wird ein Wrapper-Objekt sein, das über das Array Wraps, rief ich meine „EmbedPost“.

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

einen int namens ID in meiner EmbedPost Klasse Durch die Definition, Ich schaffe effektiv ein Objekt, wenn ich zu JSON umgewandelt würde wie folgt aussehen:

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

Dies ist effektiv eine JSON-String, sieht sehr ähnlich aus, was Uipko in seiner Lösung verwendet hat.

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

Schritt 2:

Sie bestehen nun SpringAndroidSpiceService verwenden.

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

} 

Seien Sie sicher, dass sowohl die EmbedPost.class und Post.class zu Ihrem classCollection hinzufügen, wie ORMLite nicht ihre Arbeit tun können, ohne dass Sie beide persistierenden. Sie haben ForeignKeys verwendet, als Sie Ihre Objekte geschrieben haben, und diese Fremdschlüssel müssen an etwas gebunden sein, daher müssen beide Klassen bestehen bleiben.

Wenn Sie Probleme bekommen, versuchen Sie es mit dem Logcat. Möglicherweise müssen Sie alle Nachrichten lesen und nicht nur die Fehler. Siehe meinen Beitrag hier zu sehen, wie alle logcat Nachrichten zu lesen:

Robospice storing object that extends ArrayList in database via Ormlite