I have JSON data with following structure. I have tried creating POJOs with same structure and with same names. I have taken a DTO which contains a list (of DTOs with structure of the numeral objects in the following JSON) and a String "Notice". I am not able to get the data in the DTO.
{
"notice": "This API is in a pre-launch state, and will go through significant changes.",
"1": {
"next_renewal_date": "2014-08-01",
"next_renewal_fee": {
"price": "800.0",
"currency": "USD"
},
"next_renewal_description": "1st Annuity - Official Fee",
"next_per_claim_fee": {
"price": "0.0",
"currency": "USD",
"free_claims": 0,
"claim_type": "claims_count"
},
"next_agent_fee": {
"price": "0.0",
"currency": "USD"
},
"grace_period_end_date": "2015-02-01"
},
"2": {
"next_renewal_date": "2018-08-01",
"next_renewal_fee": {
"price": "1800.0",
"currency": "USD"
},
"next_renewal_description": "2nd Annuity - Official Fee",
"next_per_claim_fee": {
"price": "0.0",
"currency": "USD",
"free_claims": 0,
"claim_type": "claims_count"
},
"next_agent_fee": {
"price": "0.0",
"currency": "USD"
},
"grace_period_end_date": "2019-02-01"
}
}
POJO:
public class RenewalAPICallListDTO {
private Map<Integer,JSONCallDto> apiCallList;
public Map<Integer, JSONCallDto> getApiCallList() {
return apiCallList;
}
public void setApiCallList(Map<Integer, JSONCallDto> apiCallList) {
this.apiCallList = apiCallList;
}
private String notice;
public String getNotice() {
return notice;
}
public void setNotice(String notice) {
this.notice = notice;
}
}
Method call:
Gson gson = new Gson();
RenewalAPICallListDTO respDto = gson.fromJson(response1.toString(), RenewalAPICallListDTO.class);
What you are looking for can be achieve with Jackson with a custom deserializer, as the following:
public class CustomDeserializer extends JsonDeserializer<RenewalAPICallListDTO> {
private static final ObjectMapper mapper = new ObjectMapper();
static {
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
#Override
public RenewalAPICallListDTO deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException {
JsonNode node = jp.getCodec().readTree(jp);
Iterator<Entry<String, JsonNode>> nodeIterator = node.fields();
RenewalAPICallListDTO dto = new RenewalAPICallListDTO();
Map<Integer, JsonCallDto> map = new HashMap<>();
while (nodeIterator.hasNext()) {
Map.Entry<String, JsonNode> entry = nodeIterator.next();
if (entry.getKey().equalsIgnoreCase("notice")) {
dto.setNotice(entry.getValue().toString());
} else {
map.put(Integer.parseInt(entry.getKey()), mapper.readValue(entry.getValue().toString(), JsonCallDto.class));
}
}
dto.setApiCallList(map);
return dto;
}
}
Usage:
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(RenewalAPICallListDTO.class, new CustomDeserializer());
mapper.registerModule(module);
RenewalAPICallListDTO dto = mapper.readValue(JSON, RenewalAPICallListDTO.class);
}
The final dto will be correctly serialized like you want, even with the correct types already set.
The json and POJO do not match. The attribute apiCallList is missing in your JSON string.
The structure should be like:
{
"notice": "random string",
"apiCallList": {
"1": {
"next_renewal_date": "2014-08-01",
...
},
"2": {
"next_renewal_date": "2014-08-01",
....
}
}
}
I have found a way. Thanks for the help.
I have converted the JSON into Hashmap using :
Map data = mapper.readValue(json,Map.class);
and then iterated the map, using the objects to populate POJOs.
Related
I want to read this JSON using ObjectMapper:
{
"basePath": "/v1",
"models": {
"Course":{
"number": "integer",
"name": "string",
"description": "string"
},
"Department": {
"name": "string",
"code": "string"
}
}
}
I used Jackson ObjectMapper like this:
ObjectMapper mapper = new ObjectMapper();
InputStream inputStream = Input.class.getResourceAsStream("/input.json");
Input input = mapper.readValue(inputStream, Input.class);
Where Input is:
public class Input {
String basePath;
Map<String, Map<String, Map<String, String>>> models;
public String getBasePath() {
return basePath;
}
public void setBasePath(String basePath) {
this.basePath = basePath;
}
public Map<String, Map<String, Map<String, String>>> getModels() {
return models;
}
public void setModels(Map<String, Map<String, Map<String, String>>> models) {
this.models = models;
}
}
But I am getting JSON Mapping Error.
Can not instantiate value of type [map type; class java.util.LinkedHashMap, [simple type, class java.lang.String] -> [simple type, class java.lang.String]] from JSON String; no single-String constructor/factory method
What am I doing wrong here?
The provide json structure does not matches with the models map structure. You have two options for it either change in Map or change in json.
Map<String, Map<String, String>> models;
If change in json structure like below.
{
"basePath": "/v1",
"models": {
"Course":{
"Details":{
"number": "integer",
"name": "string",
"description": "string"
}
}
}
}
I think better to change in Map thing rather to change the JSON structure.
I got a null object attributes after deserialization of a json response.
Developing under android, I'm using retrofit2 , moshi as converter (https://github.com/kamikat/moshi-jsonapi ) .
When debugging ,I saw a json response fully retrieved (not null attributes),but deserialization fails. Should I use GSON instead?
Here's my retrofit builder I use to make my json call: (no issue)
public static JsonServerInterface getSimpleClient(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_AUTH_URL)a
.addConverterFactory(MoshiConverterFactory.create())
.build();
JsonServerInterface webServer=retrofit.create(JsonServerInterface.class);
return webServer;
}
My api json call,response contain UserModel with null attributes(deserialization fails without any error)
signInCall.enqueue(new Callback<UserModel>(){
#Override
public void onResponse
(Call<UserModel> call, Response<UserModel> response)
{
response.message();
}
}
My UserModel (as required by moshi ,but I think it lacks something):
#JsonApi(type = "users")
public class UserModel extends Resource {
#Json(name = "auth-token")
private String authToken;
#Json(name = "firstname")
private String firstname;
#Json(name = "lastname")
private String lastname;
#Json(name = "email")
private String email;
#Json(name = "created-at")
private String createdAt;
#Json(name = "updated-at")
private String updatedAt;
private HasMany<ActivityModel> activities;
My json response I saw when debugging http response, I retrieve without any trouve,but moshi sucks to deserialize it,and no errors are raised:
{
"data": {
"id": "21",
"type": "users",
"attributes": {
"auth-token": "t8S3BTqyPwN3T4QDMY1FwEMF",
"firstname": "aymen",
"lastname": "myself",
"email": "aymen.myself#gmail.com",
"created-at": "2017-11-13T22:52:39.477Z",
"updated-at": "2017-11-13T23:21:09.706Z"
},
"relationships": {
"activities": {
"data": [
{
"id": "81",
"type": "activities"
}
]
}
}
},
"included": [
{
"id": "81",
"type": "activities",
"attributes": {
"title": "activity 10",
"description": "how to draw a circle",
"start-at": "2017-11-13T23:06:13.474Z",
"duration": 10,
"created-at": "2017-11-13T23:06:32.630Z",
"updated-at": "2017-11-13T23:06:32.630Z"
},
"relationships": {
"user": {
"data": {
"id": "21",
"type": "users"
}
}
}
}
]
}
I find the solution after lot of hours:
I should use "Document" instead of UserModel
interface:
#POST("sign-in.json")
Call<Document> signIn(#Body Credentials credentials);
when calling:
signInCall.enqueue(new Callback<Document>(){
#Override
public void onResponse(Call<Document> call, Response<Document> response) {
hope it helps
I have a use case where I want the JSON to be converted to string as it is, but it is failing and giving me null, here is my POJO:
#Data
#JsonSnakeCase
#JsonIgnoreProperties(ignoreUnknown = true)
public class DocumentTemplateRequest {
#Enumerated(EnumType.STRING)
private TemplateState state;
#JsonDeserialize(using = JsonAsStringDeserializer.class)
private String inputSchema;
}
the Json I am using as payload:
{
"state": "staging",
"input_schema": {
"title": "Person",
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
}
},
"required": ["firstName", "lastName"]
}
}
I am using object mapper for mappings:
ObjectMapper objectMapper = new ObjectMapper();
DocumentTemplateRequest documentTemplateRequest = null;
try {
documentTemplateRequest = objectMapper.readValue(str, DocumentTemplateRequest.class);
} catch (IOException e) {
e.printStackTrace();
}
and here is my deserializer:
public class JsonAsStringDeserializer extends JsonDeserializer<String> {
#Override
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
TreeNode tree = jsonParser.getCodec().readTree(jsonParser);
return tree.toString();
}
}
and the results of deserialization is :
state : staging
inputSchema: null
why inputSchema is coming as null, what am I missing?
it is with the property?
you are missing underscroe. input_schema is different from inputSchema.
either use the same property name everywhere you use it or use jsonproperty annotation to be sepecific.
I'm trying to parse this json captured through an API of my client:
[
{
"pagination": {
"page": 7,
"total_pages": 11,
"entries": 100,
"total_entries": 1007
},
"logical_numbers": [
{
"logical_number": {
"id": 50095,
"number": "524103650",
"app_version_ids": [
1427,
1230,
847
],
"created_by": 1510,
"created_via": "interface",
"group_id": 526,
"created_at": "2016-03-21T15:54:30.670-03:00",
"updated_at": "2016-03-21T15:54:30.682-03:00"
}
},
{
"logical_number": {
"id": 44593,
"number": "524103627",
"app_version_ids": [
1427,
1230,
847
],
"created_by": 1510,
"created_via": "interface",
"group_id": 526,
"created_at": "2016-02-26T10:02:20.561-03:00",
"updated_at": "2016-02-26T10:02:20.608-03:00"
}
}
]
}
]
Here are the classes I created for this work:
import java.io.FileReader;
import java.util.ArrayList;
import com.google.gson.Gson;
public class Test {
public static void main(String[] args) {
Gson gson = new Gson();
Pagination[] pagination = gson.fromJson(new FileReader("input1.json"), Pagination[].class);
System.out.println(gson.toJson(pagination));
}
}
class Pagination {
Long page;
Long total_pages;
Long entries;
Long total_entries;
ArrayList<LogicalNumbers> logicals;
}
class LogicalNumbers {
int id;
String number;
ArrayList<String> app_version_ids = new ArrayList<>();
String created_by;
String created_via;
String group_id;
String created_at;
String updated_at;
}
When I run this code, I get the following result:
[{}]
I'm not succeeding in the parsings. Can anybody help me?
Thanks.
After exploring the json I found the reason of the empty deseralization...
you have two small problems...
1st one:
your json is actually an array with one object that contains a Pagination
object and a logical numbers array
2nd: the POJO description of the json schema is not correct..
after a while I found a solution:
Try:
class Foo {
private Pagination pagination;
private List<LogicalNumbers> logical_numbers;
}
class Pagination {
Long page;
Long total_pages;
Long entries;
Long total_entries;
}
class LogicalNumbers {
Ln logical_number;
}
class Ln {
int id;
String number;
List<String> app_version_ids = new ArrayList<>();
String created_by;
String created_via;
String group_id;
String created_at;
String updated_at;
}
and then
public static void main(String[] args) {
Gson gson = new Gson();
Foo[] pagination = gson.fromJson(new FileReader("input1.json"), Foo[].class);
// Pagination[] pagination = gson.fromJson(new FileReader("input1.json"), Pagination[].class);
System.out.println(gson.toJson(pagination));
}
colleagues!
We want to write Rest Client to service which follow the HATEOAS principle. So we have the following HAL+JSON representation and we want to deserialize it using spring-hateoas :
{
"id": "1",
"title": "album title",
"artistId": "1",
"stockLevel": 2,
"_links": {
"self": {"href": "http://localhost:8080/rest/albums/1"},
"artist": {"href": "http://localhost:8080/rest/artist/1"}
},
"_embedded": {
"albums": [{ //can be array or object
"id": "1",
"title": "album title",
"artistId": "1",
"stockLevel": 2,
"_links": {
"self": {"href": "http://localhost:8080/rest/albums/1"}
}
}],
"artist": { //can be array or object
"id": "1",
"name": "artist name",
"_links": {
"self": {"href": "http://localhost:8080/rest/artist/1"}
}
} //....
}
}
We expected the java object like this:
HalResource {
Resource<Album> //entity
List<Link> // _links
List<Resource<BaseEntity>>{ //_embedded
Resource<Album>
Resource<Artist>
....
}
}
So we have custom resource representation with embedded(list of resources) and entity(single resource):
#XmlRootElement(name = "resource")
public class HalResource<EntityType, EmbeddedType> extends Resources<EmbeddedType> {
#JsonUnwrapped
private EntityType entity;
public HalResource() {
}
public HalResource(Iterable<EmbeddedType> content, Link... links) {
super(content, links);
}
public EntityType getEntity() {
return entity;
}
public void setEntity(EntityType entity) {
this.entity = entity;
}
}
DTO classes:
public abstract class BaseEntity{}
#XmlRootElement(name = "album")
public class Album extends BaseEntity {
private String id;
private String title;
private String artistId;
private int stockLevel;
// getters and setters...
}
#XmlRootElement(name = "artist")
public class Artist extends BaseEntity {
private String id;
private String name;
// getters and setters...
}
And we want to get something like this, where Entity will be Artist or Album, but HalResourcesDeserializer return Resource.class with null content.
HalResource<Album, Resource<Entity>> resources =
restClient.getRootTarget().path("albums/1").queryParam("embedded", true).request().accept("application/hal+json")
.get(new GenericType<HalResource<Album, Resource<Entity>>>() {});
By using #JsonTypeInfo and #JsonSubTypes anotations we successfully deserialized our JSON(you can see the example on the github), but we don't want to have some additional type filds and anotattions in our DTO and JSON format.
We see one solution that is create a custom deserializer which can processing that.
So the question is: What is the convenient way to deserialize our JSON(links + embedded container) using spring-hateoas?
We use spring-hateoas 0.16v(but we tried 0.19v) and glassfish jersey 2.22.1
Thank you!