2013-04-05 5 views
5

Sto usando RoboSpice con Spring per Android e vorrei mantenere una matrice JSON di oggetti con OrmLite. GSON viene utilizzato per il marshalling JSON. Con la memorizzazione nella cache predefinita, tutto funziona come previsto. Ma a OrmLite non sembra piacere l'array di oggetti.RoboSpice persiste array JSON con OrmLite

Questa è una versione semplificata del JSON:

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

vorrei persistere questo nel seguente oggetto:

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

    // getters and setters 
    ... 
} 

Sulla base dell'esempio RoboSpice OrmLite ho creato il seguente Classe GsonSpringAndroidSpiceService per aggiungere OrmLite CacheManager. Questo è dove inizia il problema.

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

Il risultato è il seguente errore:

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

Quando cambio classCollection.add(Foo.class);-classCollection.add(Foo[].class); ricevo il seguente errore:

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; 

Chiunque un'idea come gestire una matrice JSON con OrmLite CacheManager?

+0

può essere un duplicato di http://stackoverflow.com/q/15801315/693752 – Snicolas

+0

@Snicolas Non voglio introdurre una classe di risultati in più, vedere la mia risposta sulla soluzione alternativa. – Uipko

risposta

6

Ho trovato un modo per risolvere questo problema. Ho aggiunto un oggetto risultato extra che contiene la matrice di oggetti. Ovviamente questo è possibile solo se sei in grado di manipolare il JSON. Non sono ancora molto contento di questo perché ho introdotto una classe inutile per il mio modello.

Quindi il mio JSON assomiglia:

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

E ho aggiunto la seguente classe per contenere il risultato JSON:

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

    // getters and setters 
    ... 
} 

aggiunto anche il rapporto estera della classe 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

Bello, varrebbe la pena accettare il tuo risponditore. Tuttavia, per le persone che non possono modificare il json, non c'è alternativa: devi introdurre una nuova classe per avvolgere la lista. – Snicolas

+0

Per la cronaca: ero alle prese con questo problema e avevo "private ForeignCollection risultato" e non funzionava. La modifica di 'ForeignCollection' in' Collection' ha risolto il problema. – Nasir

+0

@Snicolas, quale sarebbe la soluzione se non ho bisogno di cambiare l'oggetto JSON? –

3

Ho trovato il modo che funziona per me. Non ho cambiato il mio 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

Bello! Puoi darci l'output del tuo JSON per favore? – Guicara

+0

Puoi trovarlo qui. https://api.github.com/repos/octo-online/robospice/contributors –

+1

L'esempio completo può essere trovato qui https://github.com/blandware/android-atleap –

0

ho lottato con questo tutta l'oggi e finalmente capito come salvare una matrice JSON in un database SQLite utilizzando Robospice Primavera Android senza modificare il JSON.

questo è il mio messaggio JSON matrice restituita dal mio server:

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

Questo è simile alla JSON in questa domanda:

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

Fase 1:

Sarà necessario creare 2 classi sul lato Android.

Uno sarà l'oggetto normale che si desidera salvare dall'array. Nel mio caso, ho un oggetto chiamato "Post" e il mio server restituisce un array di "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; 

L'altro oggetto sarà un oggetto wrapper che avvolge sopra la matrice, ho chiamato il mio "EmbedPost".

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

Definendo un int chiamato ID nella mia classe EmbedPost, sto in modo efficace la creazione di un oggetto che, se mi sono convertito a JSON sarebbe simile a questa:

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

Questa è effettivamente una stringa JSON che sembra molto simile a quello che Uipko ha usato nella sua soluzione.

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

Fase 2:

Ora ostini utilizzando 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; 
    } 

} 

Assicurarsi di aggiungere sia l'EmbedPost.class e Post.class al classCollection come ORMLite non può fare il suo lavoro senza di te persistente entrambi. Hai usato ForeignKeys quando hai scritto i tuoi oggetti e queste chiavi esterne devono legarsi a qualcosa quindi entrambe le classi devono persistere.

In caso di problemi, provare a utilizzare il logcat per individuarlo. Potrebbe essere necessario leggere tutti i messaggi e non solo quelli di errore. Vedere il mio post qui per vedere come leggere tutti i messaggi logcat:

Robospice storing object that extends ArrayList in database via Ormlite