2013-04-05 15 views
5

Używam RoboSpice z Spring dla Androida i chciałbym utrzymywać tablicę obiektów JSON z OrmLite. GSON jest używany do zestawiania JSON. Przy domyślnym buforowaniu wszystko działa zgodnie z oczekiwaniami. Ale OrmLite nie lubi zestawu obiektów.RoboSpice utrzymuje tablicę JSON z OrmLite

Jest to uproszczona wersja JSON:

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

chciałbym utrzymywać to w następujący obiektu:

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

    // getters and setters 
    ... 
} 

na przykładzie RoboSpice OrmLite Utworzyłem następujące GsonSpringAndroidSpiceService klasa, aby dodać OrmLite CacheManager. Tutaj zaczyna się 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; 
    } 
} 

Wynika to w następujący błąd:

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

Kiedy zmienić classCollection.add(Foo.class); do classCollection.add(Foo[].class); pojawia się następujący błąd:

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; 

, ktoś pomysł jak obsługiwać tablicę JSON z OrmLite CacheManager?

+0

Może być duplikatem http://stackoverflow.com/q/15801315/693752 – Snicolas

+0

@Snicolas Nie chcę przedstawić dodatkowa klasa wyników, zobacz moją odpowiedź na temat obejścia tego problemu. – Uipko

Odpowiedz

6

Znalazłem pracę związaną z tym problemem. Dodałem dodatkowy obiekt wyniku, który zawiera tablicę obiektów. Oczywiście jest to możliwe tylko wtedy, gdy jesteś w stanie manipulować JSON. Wciąż niezbyt mnie to cieszy, ponieważ wprowadziłem do mojego modelu bezużyteczną klasę.

Więc mój JSON wygląda następująco:

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

I dodałem następujące klasy, aby utrzymać wynik JSON:

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

    // getters and setters 
    ... 
} 

Dodano także obcy relacji The class 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

Przyjemnie, byłoby warto zaakceptować swojego rozmówcę. Niemniej jednak, dla osób, które nie mogą modyfikować json, nie ma alternatywy: musisz wprowadzić nową klasę, aby zawinąć listę. – Snicolas

+0

Dla przypomnienia: zmagałem się z tym problemem i miałem 'private ForeignCollection result' i to nie działało. Zmiana 'ForeignCollection' na' Collection' naprawiła problem. – Nasir

+0

@Snicolas, jakie byłoby rozwiązanie, gdybym nie musiał zmieniać obiektu Json? –

3

Znalazłem sposób, który działa dla mnie. Nie zmieniłem mojego jsona.

@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

Nice! Czy możesz podać nam wynik twojego JSON? – Guicara

+0

Możesz go znaleźć tutaj. https://api.github.com/repos/octo-online/robospice/contributors –

+1

Pełny przykład można znaleźć tutaj https://github.com/blandware/android-atleap –

0

Walczyłem z tym cały dzisiejszy i wreszcie zorientowali jak zapisać tablicę JSON w SQLite bazy danych przy użyciu Robospice Wiosna Android bez modyfikacji JSON.

To jest mój post JSON tablica wróciła z moim serwerze:

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

Jest to podobne do JSON w tej kwestii:

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

Krok 1:

Musisz utwórz 2 klasy po stronie Androida.

Jeden będzie normalnym obiektem, który chcesz zapisać z tablicy. W moim przypadku mam obiekt o nazwie "Post", a mój serwer zwraca tablicę "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; 

Innym obiektem będzie obiekt otoki, który owija się wokół tablicy, nazwałem ją "EmbedPost".

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

Definiując int o nazwie ID w mojej klasie EmbedPost, mam skutecznie tworząc obiekt, że gdybym konwertowane do formatu JSON będzie wyglądać następująco:

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

To jest faktycznie ciąg JSON, które wygląda bardzo podobnie do tego, co Uipko używał w swoim rozwiązaniu.

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

Krok 2:

teraz utrzymują go przy 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; 
    } 

} 

Pamiętaj, aby dodać zarówno EmbedPost.class i Post.class do classCollection jak ORMLite nie może zrobić swoją pracę bez ciebie utrzymujących oba. Użyłeś ForeignKeys podczas pisania swoich obiektów, a te zagraniczne klucze muszą być powiązane z czymś, więc obie klasy muszą się utrzymywać.

Jeśli napotkasz problemy, spróbuj użyć logcat, aby to rozszyfrować. Być może będziesz musiał przeczytać wszystkie wiadomości, a nie tylko te, które zawierają błędy. Patrz mój post tutaj, aby zobaczyć, jak czytać wszystkie wiadomości logcat:

Robospice storing object that extends ArrayList in database via Ormlite