Reputation: 99
I'm getting results from a REST API, it is a list of json object representing users with nested json objects inside each user. My problem is that nested properties names do not correspond to the bean properties I got in my code. But they are so inappropriate that I really want to not keep the API nested properties names...
I am using genson 1.5 with java 8, and lombok for my beans. I tried to use simple deserializer and then a Converter but without success.
Here is an example of what I receive from the API:
[
{
"FirstName": "Jack",
"LastName": "Sparrow",
"Adress": {
"String1": "Toulon",
"String2": "France",
"String3": "83",
}
},
{
"FirstName": "I am",
"LastName": "Groot",
"Adress": {
"String1": "Marseille",
"String2": "France",
"String3": "13",
}
},
]
Here is the bean I want to have as a new format:
@Data
public class User {
private String firstName;
private String lastName;
private String country; //this represents String2 from the API
}
I already tried those solutions:
private Genson genson = new Genson();
public List<User> getUserList() {
Response response = api.target(url)...get();
List<User> users = genson.deserialize(response.readEntity(String.class), new GenericType<List<User>>(){});
return users;
}
private Genson genson = new GensonBuilder().withConverters(new UserConverter()).create();
public List<User> getUserList() {
Response response = api.target(url)...get();
List<User> users = this.genson.deserialize(response.readEntity(String.class), new genericType<List<User>>(){});
return users;
}
public class UserConverter implements Converter<User> {
public User deserialize(ObjectReader reader, Context ctx) throws Exception {
User user = new User();
reader.beginObject();
while (reader.hasNext()) {
reader.next();
if ("FirstName".equals(reader.name())) {
user.setFirstName(reader.valueAsString());
} else if ("LastName".equals(reader.name())) {
user.setLastName(reader.valueAsString());
} else if ("Adress".equals(reader.name())) {
reader.beginObject();
while (reader.hasNext()) {
if ("String2".equals(reader.name())) {
user.setCountry(reader.valueAsString());
} else {
reader.skipValue();
}
}
reader.endObject();
} else {
reader.skipValue();
}
}
reader.endObject();
return user;
}
@Override
public void serialize(User object, ObjectWriter writer, Context ctx) throws Exception {
// TODO Auto-generated method stub
}
}
The error is:
com.owlike.genson.JsonBindingException: Could not deserialize to type interface java.util.List
at com.owlike.genson.Genson.deserialize(Genson.java:384)
...
Caused by: com.owlike.genson.stream.JsonStreamException: Illegal character at row 0 and column 660 expected } but read '{' !
at com.owlike.genson.stream.JsonReader.newWrongTokenException(JsonReader.java:942)
...
Genson is giving an example at http://genson.io/Documentation/UserGuide/#custom-serde but they read a list of integer as a value this is why I tried a nested while for nested json...
If someone have ideas on how to deal with my problem, thank you very much !
Upvotes: 0
Views: 548
Reputation: 99
@eugen Thank you for your answer, I tried @JsonProperty above each of my bean parameters but unfortunately it was not working.
Then a collegue came and we added in the UserConverter:
private GenericType<Map<String, String>> adressMap = new GenericType<Map<String, String>>() {};
and changed the second while for:
else if ("Adress".equals(reader.name())) {
user.string2Value((ctx.genson.deserialize(adressMap, reader, ctx)).get("String2"));
}
this is actually working.
Upvotes: 1
Reputation: 5916
Your problem is that the name of the attributes in the JSON is different from what you have in the code. Note in your JSON the first letter is upper case.
You have a couple options around that:
- Rename them in your JSON
- Rename on the code side with @JsonProperty("newname")
or using builder.rename(currentName, newName)
.
- Implement a custom PropertyNameResolver that delegates name resolution to ConventionalBeanPropertyNameResolver and then just changes the first letter to upper case.
You can implement custom converters as you started, but this will be quite some work if you need to do it for each type.
I recommend implementing the custom name resolver.
Upvotes: 0