I'm trying to get the Java class for deserializing this:
API Response
I'm using http://www.jsonschema2pojo.org/ for getting the java classes I need. But with this json response I get this:
public class CatalogueResponse {
#SerializedName("0")
#Expose
private uex.asee.fjrm.multimediapp.api.pojos.catalogue._0 _0;
#SerializedName("1")
#Expose
private uex.asee.fjrm.multimediapp.api.pojos.catalogue._1 _1;
#SerializedName("2")
#Expose
private uex.asee.fjrm.multimediapp.api.pojos.catalogue._2 _2;
#SerializedName("3")
#Expose
private uex.asee.fjrm.multimediapp.api.pojos.catalogue._3 _3;
#SerializedName("4")
#Expose
private uex.asee.fjrm.multimediapp.api.pojos.catalogue._4 _4;
#SerializedName("5")
#Expose
private uex.asee.fjrm.multimediapp.api.pojos.catalogue._5 _5;
...
}
But the number of items of the json is varying, so I can't handle it that way.
I'm using gson annotations by the way.
Any ideas?
Why don't you try using a Map and then serializing it. I would suggest using a TreeMap and adding numbers as keys and values as the Catalogue object. Something like:
Map<Integer, Catalogue> map = new TreeMap<>();
map.put(0, catalogue0);
map.put(1, catalogue1);
...
// Now serialize the map.
This will generate the API response that you require.
To deserialize it using Gson, try the following:
Type mapType = new TypeToken<Map<Integer, Catalogue>>(){}.getType();
Map<Integer, Catalogue> catalogueMap = (Map<Integer, Catalogue>) gson.fromJson(json, mapType);
Related
I have this entity; transferRate is persisted as json format in database :
#Entity
#Data
public class Currency implements Serializable {
#Id
private String currencyIsoCode;
private String currencyIsoNum;
#Convert(converter = JpaConverterJson.class)
private Map<String, Object> transferRate = new HashMap();
}
and in the client project iam using Rest Template to get list of currencies like that
ResponseEntity<List<Currency>> listResponse =
restTemplate.exchange(RestApiConstants.BASE_URL + CurrenciesRestApiConstants.LIST_CURRENCIES,
HttpMethod.GET, null, new ParameterizedTypeReference<>() {
});
currencyList = listResponse.getBody();
But iam getting this error
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `double` from Object value (token `JsonToken.START_OBJECT`)
The class in the client side is like that
#Data
public class Currency implements Serializable {
private String currencyIsoCode;
private String currencyIsoNum;
private Map<String, Object> transferRate;
}
What iam I doing wrong
Thank you in advance
Your field is defined as a Map<String, Object>, so Jackson tries to deserialize the map value as an Object. From JSON point of view, an object is a set of properties in curly braces. This is where the error comes from:
Cannot deserialize value of type `double` from Object value (token `JsonToken.START_OBJECT`)
Apparently on the client side you send a numeric value, so you need to define transferRate with the numeric type, e.g.:
#Convert(converter = JpaConverterJson.class)
private Map<String, Double> transferRate = new HashMap();
And use a similar type on the client:
private Map<String, Double> transferRate;
I have sample json data like below
{"data":{"detection":[{"category":"building","coordinates":{"xmin":"0.31","ymin":"0.42","ymax":"0.82","xmax":"0.89"},"accuracy":"0.66"}]}}
Trying to parse data field in jackson parser and created ObjectCategories class(setter getter) for its values.
#JsonProperty("categories")
private List<ObjectCategory> categories;
#SuppressWarnings("unchecked")
#JsonProperty(DATA)
private void unpackNested(Map<String,Object> data) {
this.categories = (ArrayList<ObjectCategory>) data.get("detection");
}
If we execute the above code, getting this exception - getCategories().get(0).getAccuracy() to java.util.LinkedHashMap cannot be cast to ObjectCategory
getCategories().get(0) returns Map value. How to parse with my ObjectCategory class.
You can convert the value if you originally deserialized it to map.
this.categories = objectMapper
.convertValue(data.get("detection"),
new TypeReference<List<ObjectCategory>>() {});
Hello i got this Json string
{"NexusResource":{"resourceURI":"http://nexus.ad.hrm.se/nexus/service/local/repositories/snapshots/content/se/hrmsoftware/hrm/hrm-release/16.1-SNAPSHOT/","relativePath":"/se/hrmsoftware/hrm/hrm-release/16.1-SNAPSHOT/","text":"16.1-SNAPSHOT","leaf":false,"lastModified":"2018-04-09 12:23:59.0 UTC","sizeOnDisk":-1}}
I want to convert this to an object of a class named NexusResource that looks like this
public class NexusResource {
#JsonProperty("resourceURI") private String resourceURI;
#JsonProperty("relativePath") private String relativePath;
#JsonProperty("text") private String text;
#JsonProperty("leaf") private Boolean leaf;
#JsonProperty("lastModified") private String lastModified;
#JsonProperty("sizeOnDisk") private Integer sizeOnDisk;
#JsonIgnore private Map<String, Object> additionalProperties = new HashMap<>();
}
i try to convert it with an ObjectMapper
ObjectMapper mapper = new ObjectMapper();
NexusResource resource = mapper.readValue(version, NexusResource.class);
were version is the Json string but when i log resource all i get is null (null) even though version got all the data.
You can configure your ObjectMapper to unwrap the root value, in order to de-serialize into your POJO.
E.g.:
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
See API.
You could also work around that by modifying your POJO (see Karol's answer).
Failure to choose either should result in a com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException being thrown, with message: Unrecognized field "NexusResource".
NexusResource is not a root of your JSON but a key. To make your Java mapping work you should define a wrapping type:
public class NexusResources {
#JsonProperty("NexusResource") private NexusResource root;
...
}
and then use it to map:
ObjectMapper mapper = new ObjectMapper();
NexusResources root = mapper.readValue(version, NexusResources.class);
NexusResource resource = root.getRoot();
The problem is that the JSON does not match the class you are trying to parse. Please notice that the JSON has a field called "NexusResource" that has all the other fields. Whereas the class NexusResource.class just has the fields. Two things you can do. Change the JSON to match NexusResource.class, or create a new class that matches the JSON.
1) Change the json to the following.
{"resourceURI":"http://nexus.ad.hrm.se/nexus/service/local/repositories/snapshots/content/se/hrmsoftware/hrm/hrm-release/16.1-SNAPSHOT/","relativePath":"/se/hrmsoftware/hrm/hrm-release/16.1-SNAPSHOT/","text":"16.1-SNAPSHOT","leaf":false,"lastModified":"2018-04-09 12:23:59.0 UTC","sizeOnDisk":-1}
2) Create new class that actually matches your Json.
class NexusResourceJson {
#JsonProperty("NexusResource ")
NexusResource resource;
public NexusResource getResource() {return resource;}
}
ObjectMapper mapper = new ObjectMapper();
NexusResource resource = mapper.readValue(version, NexusResourceJson.class).getResource();
I couldn't find an example how to map the following json:
{
"id":1,
"name":"hugodesmarques",
"age":30,
}
To the following java object using jackson:
public class EntityDto {
private Map<String, Object> content;
}
Notice the dto is just a wrapper. What I'm trying to achieve is to have an object EntityDto with a Map{name=>"hugodesmarques", age=>30, id=>1}.
I want to avoid having to map each json field to an object map.
A step back
First of all, the JSON you posted in you question is invalid: there's a comma after 30 and it shouldn't be there. Fix your JSON otherwise Jackson won't parse it:
{
"id": 1,
"name": "hugodesmarques",
"age": 30
}
Parsing the JSON with Jackson
Add a constructor annotated with #JsonCreator to the EntityDto class, as following:
public class EntityDto {
private Map<String, Object> content;
#JsonCreator
public EntityDto(Map<String, Object> content) {
this.content = content;
}
// Getters and setters omitted
}
Then parse the JSON using ObjectMapper:
String json = "{\"id\":1,\"name\":\"hugodesmarques\",\"age\":30}";
ObjectMapper mapper = new ObjectMapper();
EntityDto entityDto = mapper.readValue(json, EntityDto.class);
Structure of class must be like structure of JSON:
public class EntityDto {
int id;
String name;
int age;
}
Jackson can read JSON as a HashMap:
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> map = mapper.readValue("{\"id\":1, \"name\": \"One\"}", HashMap.class);
EntityDto dto = new EntityDto();
dto.setContent(map);
I want to serialize my Example class below into JSON using GSON.
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.LinkedHashMap;
public class Example
{
private LinkedHashMap<String,Object> General;
private static final String VERSION="Version";
private static final String RANGE="Range";
private static final String START_TIME="Start_Time";
private static final String END_TIME="End_Time";
public Example() {
General = new LinkedHashMap<String,Object>();
General.put(VERSION, "0.1");
LinkedHashMap<String,String> Range = new LinkedHashMap<String, String>();
Range.put(START_TIME, "now");
Range.put(END_TIME, "never");
General.put(RANGE, Range);
}
public String toJSON() {
Gson gson = new GsonBuilder().serializeNulls().create();
return gson.toJson(this);
}
}
I expected to get the following output:
{"General":{"Version":"0.1","Range":{"Start_Time":"now","End_Time":"never"}}}
But calling the function toJSON() returns
{"General":{"Version":"0.1","Range":{}}}
It seems that GSON cannot serialize the Map Range inside the Map General. Is this a limitation of GSON or am I doing something wrong here?
The reason why Nishant's answer works is because Gson's default constructor enables all kind of stuff per default that you would otherwise have to manually enably using the GsonBuilder.
From the JavaDocs:
Constructs a Gson object with default configuration. The default configuration has the following settings:
The JSON generated by toJson methods is in compact representation. This means that all the unneeded white-space is removed. You can change this behavior with GsonBuilder.setPrettyPrinting().
The generated JSON omits all the fields that are null. Note that nulls in arrays are kept as is since an array is an ordered list. Moreover, if a field is not null, but its generated JSON is empty, the field is kept. You can configure Gson to serialize null values by setting GsonBuilder.serializeNulls().
Gson provides default serialization and deserialization for Enums, Map, java.net.URL, java.net.URI, java.util.Locale, java.util.Date, java.math.BigDecimal, and java.math.BigInteger classes. If you would prefer to change the default representation, you can do so by registering a type adapter through GsonBuilder.registerTypeAdapter(Type, Object).
The default Date format is same as java.text.DateFormat.DEFAULT. This format ignores the millisecond portion of the date during serialization. You can change this by invoking GsonBuilder.setDateFormat(int) or GsonBuilder.setDateFormat(String).
By default, Gson ignores the com.google.gson.annotations.Expose annotation. You can enable Gson to serialize/deserialize only those fields marked with this annotation through GsonBuilder.excludeFieldsWithoutExposeAnnotation().
By default, Gson ignores the com.google.gson.annotations.Since annotation. You can enable Gson to use this annotation through GsonBuilder.setVersion(double).
The default field naming policy for the output Json is same as in Java. So, a Java class field versionNumber will be output as "versionNumber#quot; in Json. The same rules are applied for mapping incoming Json to the Java classes. You can change this policy through GsonBuilder.setFieldNamingPolicy(FieldNamingPolicy).
By default, Gson excludes transient or static fields from consideration for serialization and deserialization. You can change this behavior through GsonBuilder.excludeFieldsWithModifiers(int).
OK, now I see what the problem is. The default Map serializer, as you expected, does not support nested maps. As you can see in this source snippet from DefaultTypeAdapters (especially if you step through with a debugger) the variable childGenericType is set to the type java.lang.Object for some mysterious reason, so the runtime type of the value is never analysed.
Two solutions, I guess:
Implement your own Map serializer / deserializer
Use a more complicated version of your method, something like this:
public String toJSON(){
final Gson gson = new Gson();
final JsonElement jsonTree = gson.toJsonTree(General, Map.class);
final JsonObject jsonObject = new JsonObject();
jsonObject.add("General", jsonTree);
return jsonObject.toString();
}
Try this:
Gson gson = new Gson();
System.out.println(gson.toJson(General));
Not sure if you're still looking for a solution, this works for me:
import java.util.LinkedHashMap;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class Example {
// private static LinkedHashMap<String,Object> General;
private ImmutableMap General;
private static final String VERSION="Version";
private static final String RANGE="Range";
private static final String START_TIME="Start_Time";
private static final String END_TIME="End_Time";
public Example() {
LinkedHashMap<String,String> Range = new LinkedHashMap<String, String>();
Range.put(START_TIME, "now");
Range.put(END_TIME, "never");
// General.put(RANGE, Range);
General = ImmutableMap.of(VERSION, "0.1", RANGE, Range);
}
public String toJSON() {
// Gson gson = new GsonBuilder().serializeNulls().create();
Gson gson = new Gson();
return gson.toJson(this);
}
}
returns: {"General":{"Version":"0.1","Range":{"Start_Time":"now","End_Time":"never"}}}
Obviously you could use ImmutableMap.copyOf(your_hashmap)here instead
A simpler alternative would be to use Jackson instead of GSON, serialization of a nested map works out of the box:
LinkedHashMap<String, Object> general;
general = new LinkedHashMap<String, Object>();
general.put("Version", "0.1");
LinkedHashMap<String, String> Range = new LinkedHashMap<String, String>();
Range.put("Start_Time", "now");
Range.put("End_Time", "never");
general.put("Range", Range);
// Serialize the map to json using Jackson
ByteArrayOutputStream os = new ByteArrayOutputStream();
new org.codehaus.jackson.map.ObjectMapper().writer().writeValue(os,
general);
String json = os.toString();
os.close();
System.out.println(json);
Output:
{"Version":"0.1","Range":{"Start_Time":"now","End_Time":"never"}}