Java controller getting only first item from Set via JSON - java

Trying to save One to Many JPA relationship. I have written a custom controller. I am getting only the first id in giftSet and not all the ids. I have simplified the code.
My Post request-
{
"name": "Project 7",
"giftSet": [
{
"id": "1"
},
{
"id":"33"
}
]
}
class Holiday{
private String name;
private Set<GiftConfig> giftSets;
}
class GiftSet {
private Integer id;
private Holiday holiday;
}
class GiftConfig {
private Integer id;
private String name;
}
#RequestMapping(method = RequestMethod.POST, value="/api/saveholiday")
public ResponseEntity<Map<String, Holiday>> saveHoliday(#RequestBody Holiday holiday) {
System.out.println(holiday);
return null;
}
First, I add multiple GiftConfig. After that, while creating Holiday, I add details for GiftSet as well.
In debug mode, I see only id 1 in giftSet and not both ids 1 and 33.
Note- Changing Set to List is not an option.

Introduction
I see 2 problems and one possible last issue.
You are missing setters/getters in order for de-serialization to work on the JSON.
Your payload doesn't seem to be working for me.
As pcoates mentioned in a comment, you could also use #JsonAutoDetect(fieldVisibility = Visibility.ANY) - but I haven't tested this.
Finally, also be careful about having a circular reference if you convert from java back to JSON. I see that a Holiday has a set of giftSets, but a giftSet points to a holiday.
If the gitset points to the same parent holiday, this is a circular reference and will crash.
Getters and Setters
Your problem is that you are missing getters and setters.
Either use lombok and add a #data annotation or add a getter and setter .
#Data
public static class Holiday{
private String name;
private Set<GiftSet> giftSets;
}
#Data
public static class GiftSet {
private Integer id;
private Holiday holiday;
}
Payload
I used the following payload:
{
"name": "HolidaySet",
"giftSets": [
{
"id": 1111,
"holiday": {
"name": null,
"giftSets": null
}
},
{
"id": 1112,
"holiday": {
"name": null,
"giftSets": null
}
}
]
}
Quick Test
I did a quick test to see what the payload should be like.
#RequestMapping(method = RequestMethod.POST, value="/api/saveholiday")
public ResponseEntity<Map<String, Holiday>> saveHoliday(#RequestBody Holiday holiday) throws JsonProcessingException {
System.out.println(holiday);
fakeItTest();
return null;
}
private void fakeItTest() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
Set<GiftSet> giftSets2 = new HashSet<>();
GiftSet gg = new GiftSet();
gg.setId(1111);
gg.setHoliday(new Holiday());
giftSets2.add(gg);
GiftSet gg2 = new GiftSet();
gg2.setId(1112);
gg2.setHoliday(new Holiday());
giftSets2.add(gg2);
Holiday holiday2 = new Holiday();
holiday2.setName("HolidaySet");
holiday2.setGiftSets(giftSets2);
String a = objectMapper.writeValueAsString(holiday2);
System.out.println(a);
}
#Data
public static class Holiday{
private String name;
private Set<GiftSet> giftSets;
}
#Data
public static class GiftSet {
private Integer id;
private Holiday holiday;
}

Related

Why are some of the variables in POJO equal to null after converting JSON RESTful Webservice?

I am consuming a RESTful webservice that returns a JSON payload. I can successfully consume the RESTful webservice and manage to populate some of the POJO attributes with JSON data. However, some other attributes are null when they are supposed to contain a value. How can I ensure that there are no more nulls?
I have defined 4 POJO classes. I have so far debugged by systematically by testing the variables for each class. This is using Springboot 2.2.0 and Jackson-databind.
The JSON schema I am trying to consume:
{
"items":[
{
"timestamp":"2019-09-18T16:42:54.203Z",
"carpark_data":[
{
"total_lots":"string",
"lot_type":"string",
"lots_available":"string"
}
]
}
]
}
For the above, I defined 4 classes:
public class Response {
#JsonProperty
private List<items> i;
#JsonIgnoreProperties(ignoreUnknown = true)
public class items {
private String timestamp;
private List<carpark_data> cpd;
#JsonIgnoreProperties(ignoreUnknown = true)
public class carpark_data {
private List<carpark_info> cpi;
private String carpark_number;
private String update_datetime;
#JsonIgnoreProperties(ignoreUnknown = true)
public class carpark_info {
private int total_lots;
private String lot_type;
private int lots_available;
When I run the below in Spring boot Main: I get null. Is my POJO modeling OK?
Response resp = restTemplate.getForObject("")
c = resp.getItems().get(0).getCarpark_data().get(0);
log.info("The last update time for the car park data = " +
c.getUpdateDatetime());
Your model does not fit to JSON payload. If we assume that JSON payload has a structure like below:
{
"items": [
{
"timestamp": "2019-09-18T16:42:54.203Z",
"carpark_data": [
{
"total_lots": "1000",
"lot_type": "string",
"lots_available": "800"
}
]
}
]
}
We can deserialise it as below:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.util.List;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
Response response = mapper.readValue(jsonFile, Response.class);
System.out.println(response.getItems().get(0).getData().get(0));
}
}
class Response {
private List<Item> items;
//getters, setters, toString
}
class Item {
private String timestamp;
#JsonProperty("carpark_data")
private List<CarParkInfo> data;
//getters, setters, toString
}
class CarParkInfo {
#JsonProperty("total_lots")
private int totalLots;
#JsonProperty("lot_type")
private String lotType;
#JsonProperty("lots_available")
private int lotsAvailable;
//getters, setters, toString
}
Above code prints:
CarParkInfo{totalLots=1000, lotType='string', lotsAvailable=800}
Hope you find the solution.
It is in POJO, you need to check the fieldName and object structure.
Seeing the Json above, your response model returns list of items and in each item you have list of carpark_data. So, basic modelling should be like this. And you can include respective setter and getter.
public class Response {
#JsonProperty
private List<items> items;
#JsonIgnoreProperties(ignoreUnknown = true)
public class items {
private String timestamp;
private List<carpark_data> carpark_data;
#JsonIgnoreProperties(ignoreUnknown = true)
public class carpark_data {
private int total_lots;
private String lot_type;
private int lots_available;
}
You need to have fields name in POJO class same in the Json response or you can set JsonProperty for that field. Like this
#JsonProperty("items")
private List<items> i;
#JsonProperty("carpark_data")
private List<carpark_data> cpd;

Deserialize a varying number of objects into a list in Java using Jackson

My Spring Boot app makes a call to a REST API and receives a JSON with a varying number of entities. E.g.
{
"content": {
"guest_1": {
"name": {
"firstName": "a",
"lastName": "b"
},
"vip": false
},
"guest_2": {
"name": {
"firstName": "c",
"lastName": "d"
},
"vip": false
},
...more guests omitted...
}
}
There can be 1 to many guests and I don't know their number upfront. As you can see, they aren't in an array, they are objects instead.
I'd like to avoid deserializing into a class like
public class Content {
#JsonProperty("guest_1")
private Guest guest1;
#JsonProperty("guest_2")
private Guest guest2;
// More Guests here each having their own field
}
What I'd like to use is
public class Content {
private List<Guest> guests;
}
The #JsonAnySetter annotation I read about at https://www.baeldung.com/jackson-annotations looks promising but I couldn't get it to work.
3.2. Convert to an object at https://www.baeldung.com/jackson-json-node-tree-model looks also good but it didn't work out either.
I'm not sure if I can make Jackson do this in a declarative way or I should write a custom JsonDeserializer. Could you please help me?
#JsonAnySetter will work as it allows to specify a POJO type as second parameter. You could recreate the example JSON as, omitting setXXX() and getXXX() methods on POJOs for clarity:
private static class Content {
private Guests content;
}
private static class Guests {
private List<Guest> guests = new ArrayList<>();
#JsonAnySetter
private void addGuest(String name, Guest value) {
guests.add(value);
}
}
private static class Guest {
private Name name;
private boolean vip;
}
private static class Name {
private String firstName;
private String lastName;
}
With your JSON example will produce:
Content root = new ObjectMapper().readValue(json, Content.class);
root.getContent().getGuests().stream()
.map(Guest::getName)
.map(Name::getFirstName)
.forEach(System.out::println); // a, c

Retrofit 2.0, Jackson and polymorphism: Could not find creator property with name <...>

I'm currently consuming a REST API with RetroFit & Jackson. Consider the following response JSON when retrieving users based on a search query when:
One result was found
{
name: "API name",
results: {
count: 1
users: {
username: "username",
age: 15
}
}
}
Multiple results were found
{
name: "API name",
results: {
count: 2,
users: [{
username: "username1",
age: 18
}, {
username: "username2",
age: 19
}]
}
}
As you can see, the users-property contains dynamic JSON: based on the found results, the value of "users" could either be a list of user objects, or 1 user object.
As such, I've designed my Java POJOs using polymorphism, as follows:
public class UserResponse {
#JsonProperty("name")
private String apiName
#JsonProperty("results")
private AResultList resultList
//Getters & Setters
//Constructor
#JsonCreator
public UserResponse(#JsonProperty("name") String name, #JsonProperty("results") AResultList r) {
this.apiName = name;
this.resultList = r;
}
}
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "classType"
)
#JsonSubTypes({
#JsonSubTypes.Type(value = ResultObject.class, name="ResultObject"),
#JsonSubTypes.Type(value = ResultList.class, name="ResultList")
})
public abstract class AResultList {
#JsonProperty("count)
private long totalCount;
//Getters & Setters
//Constructors
#JsonCreator
public AResultList(#JsonProperty("count) long count) {
this.totalCount = count;
}
}
public class ResultObject extends AResultList {
#JsonProperty("users")
private User user;
//Getters & Setters
//Constructor
#JsonCreator
public ResultObject(#JsonProperty("count) long count, #JsonProperty("users") User u) {
super(count);
this.user = u;
}
}
public class ResultList extends AResultList {
#JsonProperty("users")
private List<User> users;
//Getters & Setters
//Constructor
#JsonCreator
public ResultObject(#JsonProperty("count) long count, #JsonProperty("users") List<User> u) {
super(count);
this.users = u;
}
}
public class User {
#JsonProperty("username")
private String username;
#JsonProperty("age")
private long userAge;
//Getters & Setters
//Constructor
#JsonCreator
public User(#JsonProperty("username") String u, #JsonProperty("age") long a) {
this.userAge = a;
this.username = u;
}
}
For your information: A snippet for instantiating RetroFit
ObjectMapper o = new ObjectMapper();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(JacksonConverterFactory.create(o))
.client(okClient)
.build();
Trying to retrieve this information, however, results in the following error:
com.fasterxml.jackson.databind.JsonMappingException: Could not find creator property with name 'count' (in class org.namespace.AResultList)
at [Source: java.io.InputStreamReader#41cd2648; line: 1, column: 1]
I've been stuck on this "dynamic data" problem for 2 days now. Already tried to use GSON library and a lot of other things but to no avail. So I'd like to ask:
- Why is Jackson causing this? Is this a bug? Some users have already asked this question but the provided solutions did not work for my case.
- Is this the correct way of handling data of which part is dynamic?
I've tested my code without the use of polymorphic classes (and only retrieving 1 User from the API) and object maps perfectly. The problem is caused by the polymorphism, but I cannot figure out how to fix it.
The polymorphism configuration you're specifying in the Jackson annotations there is suggesting a {"classType":"ResultObject",...} or {"classType":"ResultList",...} is going to be in the JSON-- which it isn't. I'm not sure of the exact cause of the error you're receiving, but it seems to be looking for the creator on the abstract class since there is not type property.
[For polymorphism, Jackson needs something to read from the JSON to determine what type of bean to deserialize at this point: you don't really have one, just the array/objectness of users. I think therefore that Jackson's polymorphism support isn't a good fit for this situation]
In fact, to allow a property to either take a single item or a list of items, you just need to enable the ACCEPT_SINGLE_VALUE_AS_ARRAY deserialization feature. However, this needs to be enabled globally, there doesn't seem to be a way to target it to a specific property.
public static final class UserResponse {
public String name;
public Results results;
public static final class Results {
public int count;
public List<User> users;
}
public static final class User {
public String username;
public int age;
}
}
#Test
public void reads_single_result() throws Exception {
ObjectReader reader = new ObjectMapper().reader(UserResponse.class)
.with(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
.with(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES).with(JsonParser.Feature.ALLOW_SINGLE_QUOTES);
UserResponse response = reader.readValue("{ name: 'API name', results: { count: 1,"
+ " users: { username: 'username', age: 15 } } }");
assertThat(response.results.users, iterableWithSize(1));
assertThat(response.results.users.get(0).username, equalTo("username"));
}
#Test
public void reads_two_results() throws Exception {
ObjectReader reader = new ObjectMapper().reader(UserResponse.class)
.with(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
.with(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES).with(JsonParser.Feature.ALLOW_SINGLE_QUOTES);
UserResponse response = reader.readValue("{ name: 'API name', results: { count: 2,"
+ " users: [{ username: 'username1', age: 18 }, { username: 'username2', age: 19 }] } }");
assertThat(response.results.users, iterableWithSize(2));
assertThat(response.results.users.get(0).username, equalTo("username1"));
assertThat(response.results.users.get(1).username, equalTo("username2"));
}
Oh, and if you want to get rid of the useless results object in there, you can do that with a converter:
public static final class UserResponseWithConverter {
public String name;
#JsonProperty("results")
#JsonDeserialize(converter = ConvertResultsToUserList.class)
public List<User> users;
public static final class Results {
public int count;
public List<User> users;
}
public static final class User {
public String username;
public int age;
}
public static final class ConvertResultsToUserList extends StdConverter<Results, List<User>> {
#Override
public List<User> convert(Results value) {
return value.users;
}
}
}
Configuring for correct serialization is left as an exercise for the reader ;)

How can I unwrap a specific field in a JSON using Jackson?

I have a JSON payload that looks like this:
{
"id": 32,
"name": "[Sample] Tomorrow is today, Red printed scarf",
"primary_image": {
"id": 247,
"zoom_url": "www.site.com/in_123__14581.1393831046.1280.1280.jpg",
"thumbnail_url": "www.site.com/in_123__14581.1393831046.220.290.jpg",
"standard_url": "www.site.com/in_123__14581.1393831046.386.513.jpg",
"tiny_url": "www.site.com/in_123__14581.1393831046.44.58.jpg"
}
}
Can I unwrap a specific field and discard all the others? In other words, can I bind this directly to a POJO like this:
public class Product {
private Integer id;
private String name;
private String standardUrl;
}
There are lots of ways. Do you need to deserialize, serialize or both?
One way to deserialize would be to use a creator method that takes the image as a tree node:
public static class Product {
private Integer id;
private String name;
private String standardUrl;
public Product(#JsonProperty("id") Integer id,
#JsonProperty("name") String name,
#JsonProperty("primary_image") JsonNode primaryImage) {
this.id = id;
this.name = name;
this.standardUrl = primaryImage.path("standard_url").asText();
}
}
The creator doesn't have to be a constructor, you could have a static method that is only used for Jackson deserialization.
You'd have to define a custom serializer to reserialize this, though (e.g. a StdDelegatingSerializer and a converter to wrap the string back up as an ObjectNode)
There are different ways to skin this cat, I hope you can use Jackson 2 for this, since it offers great ways to deserialize Json data, one of my favorites deserialization features is the one I'll show you here (using Builder Pattern) because allows you to validate instances when they are being constructed (or make them immutable!). For you this would look like this:
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.util.Map;
#JsonDeserialize(builder = Product.Builder.class)
public class Product {
private Integer id;
private String name;
private String standardUrl;
private Product(Builder builder) {
//Here you can make validations for your new instance.
this.id = builder.id;
this.name = builder.name;
//Here you have access to the primaryImage map in case you want to add new properties later.
this.standardUrl = builder.primaryImage.get("standard_url");
}
#Override
public String toString() {
return String.format("id [%d], name [%s], standardUrl [%s].", id, name, standardUrl);
}
#JsonIgnoreProperties(ignoreUnknown = true)
public static class Builder {
private Integer id;
private String name;
private Map<String, String> primaryImage;
public Builder withId(Integer id) {
this.id = id;
return this;
}
public Builder withName(String name) {
this.name = name;
return this;
}
#JsonProperty("primary_image")
public Builder withPrimaryImage(Map<String, String> primaryImage) {
this.primaryImage = primaryImage;
return this;
}
public Product build() {
return new Product(this);
}
}
}
To test it I created this class:
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class Test {
public static void main(String[] args) {
String serialized = "{" +
" \"id\": 32," +
" \"name\": \"[Sample] Tomorrow is today, Red printed scarf\"," +
" \"primary_image\": {" +
" \"id\": 247," +
" \"zoom_url\": \"www.site.com/in_123__14581.1393831046.1280.1280.jpg\"," +
" \"thumbnail_url\": \"www.site.com/in_123__14581.1393831046.220.290.jpg\"," +
" \"standard_url\": \"www.site.com/in_123__14581.1393831046.386.513.jpg\"," +
" \"tiny_url\": \"www.site.com/in_123__14581.1393831046.44.58.jpg\"" +
" }" +
" }";
ObjectMapper objectMapper = new ObjectMapper();
try {
Product deserialized = objectMapper.readValue(serialized, Product.class);
System.out.print(deserialized.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
The output is (using the override toString() method in Product:
id [32], name [[Sample] Tomorrow is today, Red printed scarf], standardUrl [www.site.com/in_123__14581.1393831046.386.513.jpg].
There are two ways to get the response you required. For both methods, we are going to use JsonView.
Create two types of JsonView:
public interface JViews {
public static class Public { }
public static class Product extends Public { }
}
First method
#JsonView(JViews.Public.class)
public class Product {
private Integer id;
private String name;
#JsonIgnore
private Image primaryImage;
#JsonView(JViews.Product.class)
public String getStandardUrl{
return this.primaryImage.getStandardUrl();
}
}
Second way
Using Jackson's #JsonView and #JsonUnwrapped together.
#JsonView(JViews.Public.class)
public class Product {
private Integer id;
private String name;
#JsonUnwrapped
private Image primaryImage;
}
public class Image {
private String zoomUrl;
#JsonView(JViews.Product.class)
private String standardUrl;
}
#JsonUnwrapped annotation flattens your nested object into Product object. And JsonView is used to filter accessible fields. In this case, only standardUrl field is accessible for Product view, and the result is expected to be:
{
"id": 32,
"name": "[Sample] Tomorrow is today, Red printed scarf",
"standard_url": "url"
}
If you flatten your nested object without using Views, the result will look like:
{
"id": 32,
"name": "[Sample] Tomorrow is today, Red printed scarf",
"id":1,
"standard_url": "url",
"zoom_url":"",
...
}
Jackson provided #JsonUnwrapped annotation.
See below link:
http://jackson.codehaus.org/1.9.9/javadoc/org/codehaus/jackson/annotate/JsonUnwrapped.html

RoboSpice persist JSON array with OrmLite

I'm using RoboSpice with Spring for Android and would like to persist a JSON array of objects with OrmLite. GSON is used for the JSON marshalling. With the default caching everything works as expected. But OrmLite doesn't seem to like the array of objects.
This is a simplified version of the JSON:
[{"id": 1, "title": "Test 1"},{"id": 2, "title": "Test 3"},{"id": 3, "title": "Test 3"}]
I would like to persist this in the following object:
#DatabaseTable
public class Foo {
#DatabaseField(id = true)
private int id;
#DatabaseField
private String title;
// getters and setters
...
}
Based on the RoboSpice OrmLite example I've created the following GsonSpringAndroidSpiceService class to add the OrmLite CacheManager. This is where the problem starts.
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;
}
}
This results in the following error:
RequestProcessor.java:174(22356): java.lang.RuntimeException: Class [Lcom.example.model.Foo; is not handled by any registered factoryList
When I change classCollection.add(Foo.class); to classCollection.add(Foo[].class);
I get the following error:
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;
Anyone an idea how to handle a JSON array with the OrmLite CacheManager ?
I've found a work around to this problem. I added an extra result object which holds the array of objects. Off course this is only possible if you are able to manipulate the JSON. Still not really happy with this because I have introduce an useless class to my model.
So my the JSON looks like:
{
"id": 1,
"result":[{"id": 1, "title": "Test 1"},{"id": 2, "title": "Test 3"},{"id": 3, "title": "Test 3"}]
}
And I added the following class to hold the JSON result:
#DatabaseTable
public class FooResult {
#DatabaseField(id = true)
private int id;
#ForeignCollectionField(eager = false)
private Collection<Foo> result;
// getters and setters
...
}
Also added the foreign relation the the Foo class:
#DatabaseTable
public class Foo {
#DatabaseField(id = true)
private int id;
#DatabaseField
private String title;
#DatabaseField(foreign = true)
private FooResult result;
// getters and setters
...
}
I have found the way which works for me. I did not changed my 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);
}
}
}
}
I struggled with this the whole of today and finally figured how to save a JSON array into a SQLite database using Robospice Spring Android without modifying the JSON.
This is my post JSON array returned from my server:
[
{
"id": "5573547af58cd75df03306cc",
"name": "Simon",
"postheader": "First Post"
},
{
"id": "55735475f58cd75df03306cb",
"name": "Tyron",
"postheader": "Second Post"
}
]
This is similar to the JSON in this question:
[{"id": 1, "title": "Test 1"},{"id": 2, "title": "Test 3"},{"id": 3, "title": "Test 3"}]
Step 1:
You will need to create 2 classes on the android side.
One will be the normal object that you want to save from the array. In my case, I have an object called "Post" and my server returns an array of "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;
The other object will be a wrapper object that wraps over the array, I called mine "EmbedPost".
#DatabaseTable
public class EmbedPost implements Serializable {
#DatabaseField(allowGeneratedIdInsert=true, generatedId=true)
private int ID;
#ForeignCollectionField(eager = false)
private Collection<Post> posts;
By defining an int called ID in my EmbedPost class, I'm effectively creating a object that if I converted to JSON would look like this:
{"id": 1, "posts": [
{
"id": "5573547af58cd75df03306cc",
"name": "Simon",
"postheader": "First Post"
},
{
"id": "55735475f58cd75df03306cb",
"name": "Tyron",
"postheader": "Second Post"
}
]}
This is effectively a JSON string that looks very similar to what Uipko used in his solution.
{
"id": 1,
"result":[{"id": 1, "title": "Test 1"},{"id": 2, "title": "Test 3"},{"id": 3, "title": "Test 3"}]
}
Step 2:
You now persist it using 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;
}
}
Be sure to add both the EmbedPost.class and Post.class to your classCollection as ORMLite cannot do its work without you persisting both. You had used ForeignKeys when you wrote up your objects and these foreign keys have to tie to something so therefore both classes must persist.
If you run into trouble, try using the logcat to figure it out. You might have to read all the messages and not just the error ones.
See my post here to see how to read all logcat messages:
Robospice storing object that extends ArrayList in database via Ormlite

Categories