I have a JSON document similar to the following:
{
"aaa": [
{
"value": "ewfwefew"
}
],
"bbb": [
{
"value": "ewfewfe"
}
]
}
I need to deserialize this into something more clean such as:
public class MyEntity{
private String aaa;
private String bbb;
}
What's the best way to unwrap each array and extract the "value" field on deserialization?
#Tim Mac's response is correct, but you can make it more elegant by writing a custom deserializer for your MyEntity class.
It should be something like this:
private class MyEntityDeserializer implements JsonDeserializer<MyEntity> {
public MyEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
JsonObject rootObj = json.getAsJsonObject();
String nid = rootObj
.get("nid")
.getAsJsonArray()
.get(0)
.getAsJsonObject()
.get("value")
.getAsString();
String uuid = rootObj
.get("uuid")
.getAsJsonArray()
.get(0)
.getAsJsonObject()
.get("value")
.getAsString();
MyEntity entity = new MyEntity(nid, uuid);
return entity;
}
}
Then you have to register the TypeAdapter with:
Gson gson = new GsonBuilder().registerTypeAdapter(MyEntity.class, new MyEntityDeserializer()).create();
And finally you just have to parse your JSON as usual, with:
MyEntity entity = gson.fromJson(yourJsonString, MyEntity.class);
Gson will automatically use your custom deserializer to parse your JSON into your MyEntity class.
If you can't change the json that you're getting, you might consider deserializing it the way it is, and then converting it to something more manageable?
public class TmpEntity {
public Value[] nid {get;set;}
public Value[] uuid {get;set;}
}
public class Value {
public string value {get;set;}
}
public class MyEntity {
public string nid {get;set;}
public string uuid {get;set;}
}
var tmp = ...; //deserialize using javascriptserializer
var converted = tmp.Select(a => new MyEntity()
{
nid = a.nid.First().value,
uuid = a.uuid.First().value
}
Related
{
"id" : "25",
"authors" :
[
{
"firstname":"Ayn",
"lastname":"Rand"
},
{
"firstname":"Mark",
"lastname" : "Twain"
}
]
}
Here is my Java class:
public class FavoriteAuthors {
public String id;
public List<Author> authors;
public static class Author {
public String firstname;
public String lastname;
}
}
I have already tried using the following 2 approaches:
FavoriteAuthors favAuthors = Json.fromJson(json, FavoriteAuthors.class);
and
ObjectMapper objectMapper = new ObjectMapper();
FavoriteAuthors favAuthors = objectMapper.readValue(json, FavoriteAuthors.class);
In both the approaches, I receive the following exception:
(no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
Could anyone please point me to the right approach here?
I need to detect which json fields are not mapped to the data model after PUT or POST requests.
For example:
If I post this:
{
"firstName": "test",
"lastName": "test 2",
"age": 25
}
and my model only have firstName and lastName, I want to list all unmapped fields, which in this example is "age" field.
Yes, that is possible using Jackson's annotation #JsonAnySetter
#JsonIgnoreProperties(ignoreUnknown = true)
public class DTO {
private String first;
private String last;
private Map<String, Object> unknown = new HashMap<>();
// getters/setters omitted
#JsonAnySetter
public void set(String name, Object value) {
unknown.put(name, value);
}
public Map<String, Object> getUnknown() {
return unknown;
}
}
Simple test:
#Test
public void testUnknown() throws Exception {
String json = "{\"first\":\"John\", \"last\":\"Doe\", \"age\":\"29\"}";
DTO dto = new ObjectMapper().readValue(json, DTO.class);
assertEquals(1, dto.getUnknown().size());
assertEquals("29", dto.getUnknown().get("age"));
}
If it's just about learning which properties are unmapped you may want to consider using this library: https://github.com/whiskeysierra/jackson-module-unknown-property
It logs unmapped properties for all mapped classes without a need to modify class itself.
I have the following json file:
{
"sqldb": [
{
"name": "mydb",
"label": "sqldb",
"plan": "sqldb_free",
"credentials": {
"port": 50000,
"db": "SQLDB",
"username": "xxxxxxx",
"host": "75.126.155.92",
"hostname": "75.126.155.92",
"jdbcurl": "jdbc:db2://75.126.155.92:50000/SQLDB",
"uri": "db2://xxxxxxx:xxxxxxx#75.126.155.92:50000/SQLDB",
"password": "xxxxxxx"
}
}
]
}
The object has following structure: list of sqldb objects, which has internal credentials object. How can I parse it by Google Gson library into single sqldb object? I mean is it possible to create by using gson's annotations, Java Object like following:
public class VcapObject{
private String name;
private String label;
private String plan;
private String port;
private String db;
private String username;
private String host;
private String hostname;
private String jdbcurl;
private String uri;
private String password;
}
which will be filled by:
VcapObject vcapObject = gson.fromJson(vcapString, VcapObject.class);
for example?
To get rid of the internal credentials object, you need a custom JsonDeserializer that copies the fields from the inner class to the outer class. There are a few different strategies you could take, but here is one that modifies the JSON tree and feeds it back to Gson.
public class VcapDeserializer implements JsonDeserializer<VcapObject> {
private static final String MERGE_FIELD = "credentials";
final private Gson gson;
public VcapDeserializer() {
gson = new Gson();
}
#Override
public VcapObject deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if(json.isJsonObject()) {
JsonObject jsonObject = json.getAsJsonObject();
if(jsonObject.has(MERGE_FIELD)) {
// We have the object, get all the fields
JsonObject mergeObject = jsonObject.get(MERGE_FIELD).getAsJsonObject();
Set<Map.Entry<String, JsonElement>> entries = mergeObject.entrySet();
for(Map.Entry<String, JsonElement> entry : entries) {
// Copy property to top level object
jsonObject.add(entry.getKey(), entry.getValue());
}
// now that we have copied the fields, remove the nested object
jsonObject.remove(MERGE_FIELD);
}
// Deserialize the top-level object
return gson.fromJson(jsonObject, VcapObject.class);
} else {
// top level is supposed to be an object
throw new IllegalStateException();
}
}
}
Then create a custom Gson instance with GsonBuilder --
Gson gson = new GsonBuilder().registerTypeAdapter(VcapObject.class, new VcapDeserializer()).create();
Note -- from your question it is unclear if you want to get rid of the top-level wrapper object. I assumed not because you did not say the array was always going to return one element. So you will still need that --
public class SqlDbWrapper {
List<VcapObject> sqldb;
}
and then deserialize with --
SqlDbWrapper sqlDbWrapper = gson.fromJson(jsonString, SqlDbWrapper.class);
You can make a wrapper class containing a Collection of VcapObject, for example VcapList. Then you can pass VcapList as class to fromJson. Add a method to VcapList to get the first if not empty.
I want to deserialize json which returns different data for different parameters.
Mostly I get:
{"posts": [{ "id" : 1, "name":"post1" },{ "id" : 1, "name":"post1" }]}
But sometimes the data returned is
{"posts": false}
I want to deserialize this as the following class
public class GetReaderResponse
{
public IEnumerable<ReaderPost> posts {get; set;}
}
public class ReaderPost
{
public int id {get; set;}
public string name{get; set;}
}
I am using C#,json.net but not able to do this correctly.
Newtonsoft.Json.JsonConvert.DeserializeObject<GetReaderResponse>(dataString);
You could build a custom converter, but an easy way to handle this would be to write an error handler that detects errors with the posts property:
var settings = new JsonSerializerSettings();
settings.Error += (sender, args) =>
{
if (string.Equals("posts", args.ErrorContext.Path, StringComparison.OrdinalIgnoreCase))
{
var currentObject = args.CurrentObject as GetReaderResponse;
currentObject.posts = Enumerable.Empty<ReaderPost>();
args.ErrorContext.Handled = true;
}
};
GetReaderResponse resp =
JsonConvert.DeserializeObject<GetReaderResponse>(json, settings);
This sets posts to Enumerable.Empty<ReaderPost>. This is still a little unsatisfying because if any error occurs, the property will be set. You could build a full custom converter to do this as a more complete solution.
Here's a converter that will take care of this:
public class PostsConverter : JsonConverter
{
public override object ReadJson(
JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
JToken val = JValue.ReadFrom(reader);
object result = null;
if (val.Type == JTokenType.Array)
{
result = val.ToObject<IEnumerable<ReaderPost>>();
}
else if (val.Type == JTokenType.Boolean)
{
result = Enumerable.Empty<ReaderPost>();
}
return result;
}
public override void WriteJson(
JsonWriter writer,
object value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert (Type type)
{
return typeof(IEnumerable<ReaderPost>).IsAssignableFrom(type);
}
public override bool CanRead
{
get { return true; }
}
}
Usage:
var settings = new JsonSerializerSettings();
settings.Converters = new [] { new PostsConverter() };
GetReaderResponse resp =
JsonConvert.DeserializeObject<GetReaderResponse>(json, settings);
Example: https://dotnetfiddle.net/i9CXwp
By using JSON.NETs built in LINQ to JSON, you can try someting like this:
JObject jObject = JObject.Parse(json);
GetReaderResponse response = new GetReaderResponse();
if (jObject["posts"] is JArray)
response = jObject.ToObject<GetReaderResponse>();
// Do something with the response object.
where json variable is the json string you need to deserialize.
try this:
public class GetReaderResponse
{
public bool posts { get; set; }
public ReaderPost[] post { get; set; }
}
After reading #Ilija's comment I think I might have found a answer. I did not want not use string literals so I modified my class GetReaderResponse to look like below:
public class GetReaderResponse
{
public dynamic posts {get; set;}
public IEnumerable<ReaderPost> Posts
{
get
{
if (posts is bool )
return new ReaderPost[0];
return posts.ToObject<IEnumerable<ReaderPost>>();
}
}
}
Does this sound fine or does it look messy?
The REST API I'm talking to is responding to some of the requests in a structure as such:
{
"_links": {
"next": "NEXT_DATA_BLOCK_URL",
"prev": "PREV_DATA_BLOCK_URL",
"self": "CURRENT_DATA_BLOCK_URL"
},
"RESPONSE_DATA_NAME": [
{
... DATA_FIELDS ...
}
]
}
Where 'RESPONSE_DATA_NAME' is the data "name" - changes according to desired request. for example, it might be 'teams' or 'messages'.
Therefore I created a generic class with the following members:
public class PagedResponse<T> {
public PagingLinks _links;
public List<T> _data;
}
Is there any way I can set up my RestAdapter so that it'll always map 'RESPONSE_DATA_NAME' to the '_data' member, no matter what the field name actually is?
Thanks ^_^
Using gson you can annotate your _data field with the #SerializedName. The parameter (value) of this annotation is the name to be used when serialising and deserialising objects. For example, the Java field _data is represented as RESPONSE_DATA_NAME in JSON.
public class PagedResponse<T> {
public PagingLinks _links;
#SerializedName(value="RESPONSE_DATA_NAME")
public List<T> _data;
}
Further see doc
If you want to control the json field then you have to write custom de-serializer as like below
public class CustomDeserializer implements JsonDeserializer<PagedResponse> {
#Override
public PagedResponse deserialize(final JsonElement json,
final Type typeOfT, final JsonDeserializationContext context)
throws JsonParseException {
Gson gson = new Gson();
PagedResponse pagedResponse = new PagedResponse<>();
List list = new ArrayList<>();
pagedResponse = gson.fromJson(json, PagedResponse.class);
Type listType = new TypeToken<List>() {}.getType();
Set<Entry<String, JsonElement>> enteries = json.getAsJsonObject().entrySet();
for (Entry<String, JsonElement> entry : enteries) {
JsonElement jsonElement = (JsonElement) entry.getValue();
if (jsonElement.isJsonArray()) {
list.add(gson.fromJson(jsonElement, listType));
}
}
pagedResponse.set_data(list);
return pagedResponse;
}
}
finally parse it
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(PagedResponse.class, new CustomDeserializer());
Gson gson = gsonBuilder.create();
gson.fromJson(Your_JSON_STRING_HERE, PagedResponse.class);
So I finally found a solution to the problem...
I created a costume de-serializer, which adds the data field to the existing JsonObject, and copies the content of the RESPONSE_DATA_NAME (which is a JsonArray).
Then I serialize it normaly with GSON simple conversion (gson.fromJson()).
It's a bit stupid but it works =P
The de-serializer's class:
public class PagedResponseDeserializer implements JsonDeserializer<PagedResponse> {
#Override
public PagedResponse deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
Gson gson = new Gson();
JsonElement value = null;
JsonObject jsonObject = json.getAsJsonObject();
Iterable<Entry<String,JsonElement>> entries = jsonObject.entrySet();
for (Entry<String, JsonElement> entry : entries) {
value = entry.getValue();
if (value.isJsonArray()) break;
}
jsonObject.add("data", value);
return gson.fromJson(jsonObject, typeOfT);
}
}