(Gson) JSON to Java objects containing ArrayList<Class> - java

I'm retrieving data from a Web Service, which returns a String with the JSON representation of my object. What happens is that my object has two ArrayList<> of other objects, besides of other simple attributes. It seems to be a problem for the Gson. I've been searching and the answers do not match my specific problem.
My code is, basically:
Verbete
public class Verbete implements Serializable{
private long id;
private List<NomesVerbete> nomes;
private List<SignificadosVerbete> significados;
private int totalAcessos = 0;
private Date dataLancamento;
private int relevancia = 0;
//getters and setters
}
NomesVerbete
public class NomesVerbete implements Serializable {
private long id;
private String nome;
private String etimologia;
//getters and setters
}
SignificadosVerbete
public class SignificadosVerbete implements Serializable{
private long id;
private String significado;
private CategoriaVerbete categoria;
//getters and setters
}
CategoriaVerbete
public class CategoriaVerbete implements Serializable{
private long id;
private String nome;
private String descricao;
private int serie;
//getters and setters
}
The conversion from Verbete to JSON gives me this String (which seems to be correct, right?):
{"id":81,"nomes":[{"id":124,"nome":"aleluia","etimologia":"asasiajisjaijs"},{"id":126,"nome":"amém","etimologia":"asasiajisjaijs"}],"significados":[{"id":67,"significado":"asasjaijsiajsoijaoisjaoisj","categoria":{"id":3,"nome":"Nada","descricao":"asuahushaus","serie":1}}],"totalAcessos":0,"dataLancamento":1382066568000,"relevancia":0}
But, when I try to convert this JSON string to Verbete, it doesn't work, comproved by the NullPointerException that I get when trying to access the object. Here's is my conversion from Json:
Gson gson = new GsonBuilder().create();
Verbete verbete = gson.fromJson(resposta[1], Verbete.class); //resposta[1] is the json string above
Could someone give me a way to go in this conversion, please?
Thank you.

do like this
final String json = "{\"id\":81,\"nomes\":[{\"id\":124,\"nome\":\"aleluia\",\"etimologia\":\"asasiajisjaijs\"},{\"id\":126,\"nome\":\"amém\",\"etimologia\":\"asasiajisjaijs\"}],\"significados\":[{\"id\":67,\"significado\":\"asasjaijsiajsoijaoisjaoisj\",\"categoria\":{\"id\":3,\"nome\":\"Nada\",\"descricao\":\"asuahushaus\",\"serie\":1}}],\"totalAcessos\":0,\"dataLancamento\":1382066568000,\"relevancia\":0}";
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Date.class,
new JsonDeserializer<Date>() {
#Override
public Date deserialize(JsonElement jsonElement, Type type,
JsonDeserializationContext context)
throws JsonParseException {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(jsonElement.getAsLong());
return calendar.getTime();
}
});
Gson gson = gsonBuilder.create();
Verbete verbete = gson.fromJson(json, Verbete.class);
System.out.println(verbete);

Related

Gson - Nested Object inside a CustomObject - java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to java.util.List

I googled and saw many question and answers but none of it are helping me. Here is the issue. I have a Class
public class ResponseData {
public static transient final int SUCCESS = 1;
public static transient final int FAILED = 0;
public String id;
public int status;
public Object data;
// Constructor, Getters and Setters
}
I'm using ResponseData as the common return object for my server and the server has many APIs. In one of the API, it is setting the data parameter to ArrayList. Then converting as json using Gson (2.8.0).
And then sending back to caller. (It's not HTTP)
public class MyServerClass {
private final Gson gson;
public MyServerClass() {
GsonBuilder builder = new GsonBuilder();
gson = builder.serializeNulls().create();
}
public String someAPI() {
ResponseData responseData = new Response("myid", ResponseData.SUCCESS, Arrays.asList("Some string value", ArrayList<MyCustomObject>, "Some other Value"));
String json = gson.toJson(response)
}
}
And the MyCustomClass is a plain POJO class with some set of attributes.
public class MyCustomClass {
private String name;
private String id;
private String createdTime;
//Constructor, Getters & Setters
}
At the receiving side I have below code.
private Gson gson = null;
GsonBuilder builder = new GsonBuilder();
gson = builder.create();
///
ResponseData response = gson.fromJson(eventData, ResponseData.class);
ArrayList list = (ArrayList) respone.getData();
String val = (String) list.get(0);
List rwData = (List) list.get(1);
for(List<List<String>> entry: rwData) { // Exception is thrown Here. How to get it as List?
//Coverting Data
}
Exception is thrown when trying to get the data as List<List<String>>. How to convert the json string properly here? I cannot use the MyCustomClass at my client layer. That's why trying list
Exception occured:com.google.gson.internal.LinkedTreeMap cannot be cast to java.util.List
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to java.util.List

How can I specify certain field to be serialized into JSON using Jackson?

I have two classes Athlete and Injury, the last one contains Athlete object, when the serialization happens I get the following JSON representation back:
{"id":X,"kindOfInjury":"...","muscle":"...","side":"...","outOfTrainig":Y,"injuryDate":"2018-Jun-02","athlete":{"id":X,"firstName":"...","lastName":"...","age":X,"email":"..."}}
I don't want to get all the information about Athlete - just an id value, like "athleteId":1, instead of getting the entire object representation.
So, I have found that I need to apply my custom Serializer which implements StdSerializer on Injury class. So this is what I got so far:
class InjurySerializer extends StdSerializer<Injury> {
public InjurySerializer() {
this(null);
}
public InjurySerializer(Class<Injury> i) {
super(i);
}
#Override
public void serialize(
Injury value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeStartObject();
jgen.writeNumberField("id", value.getId());
jgen.writeStringField("kindOfInjury", value.getKindOfInjury());
jgen.writeStringField("muscle", value.getMuscle());
jgen.writeStringField("side", value.getSide());
jgen.writeNumberField("outOfTraining", value.getOutOfTraining());
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MMM-dd");
Date date = new Date();
String ourformat = formatter.format(date.getTime());
jgen.writeStringField("injuryDate", ourformat);
jgen.writeNumberField("athleteId", value.getAthlete().getId());
jgen.writeEndObject();
}
}
And the actual Injury class:
#Entity
#Table(name = "INJURY")
#JsonSerialize(using = InjurySerializer.class)
public class Injury {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "INJURY_ID")
private Long id;
#Column(name = "KIND_OF_INJURY")
private String kindOfInjury;
#Column(name = "MUSCLE")
private String muscle;
#Column(name = "SIDE")
private String side;
#Column(name = "OUT_OF_TRAINING")
private Integer outOfTraining;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MMM-dd")
#Column(name = "INJURY_DATE")
private Date injuryDate;
#ManyToOne
#JoinColumn(name = "ATHLETE_ID")
private Athlete athlete;
So, this solution works, but it looks terrible...
Question is the following:
1) Is there any mechanism which provides me functionality to change the serialization of only ONE property which I really need, instead of writing all this tedious code, where the actual change is only in this line? :
jgen.writeNumberField("athleteId", value.getAthlete().getId());
2) Could you recommend me something to read about Jackson because at this point I have a little bit mess in my head about it?
Thanks for the patience and I'm looking forwards for your responses :)
You can use the Data Transfer Object (DTO) for that purposes.
Create a simple POJO like this:
public class InjuryDTO {
//all other required fields from Injury model...
#JsonProperty("athlete_id")
private Long athleteId;
}
And converter for it:
#Component
public class InjuryToDTOConverter{
public InjuryDTO convert(Injury source){
InjuryDTO target = new InjuryDTO();
BeanUtils.copyProperties(source, target); //it will copy fields with the same names
target.setAthleteId(source.getAthlete().getId());
return target;
}
}
You can use it like that:
#RestController("/injuries")
public class InjuryController {
#Autowired
private InjuryToDTOConverter converter;
#Autowired
private InjuryService injuryService;
#GetMapping
public InjuryDTO getInjury(){
Injury injury = injuryService.getInjury();
return converter.convert(injury);
}
}
The benefit of this approach is that you can have multiple DTOs for different purposes.
You might find it less tedious to use the #JsonIgnore annotation instead of writing a custom serializer. Take this example
public class Person {
private int id;
#JsonIgnore
private String first;
#JsonIgnore
private String last;
#JsonIgnore
private int age;
// getters and setters omitted
}
When Jackson serializes this class, it only includes the "id" property in the resulting JSON.
#Test
void serialize_only_includes_id() throws JsonProcessingException {
final var person = new Person();
person.setId(1);
person.setFirst("John");
person.setLast("Smith");
person.setAge(22);
final var mapper = new ObjectMapper();
final var json = mapper.writeValueAsString(person);
assertEquals("{\"id\":1}", json);
}
You can try manupulating json string using basic string replace method.
I ran your json and converted it to your desired format:
public static void main(String args[]) {
String json = "{\"id\":123,\"kindOfInjury\":\"...\",\"muscle\":\"...\",\"side\":\"...\",\"outOfTrainig\":Y,\"injuryDate\":\"2018-Jun-02\",\"athlete\":{\"id\":456,\"firstName\":\"...\",\"lastName\":\"...\",\"age\":14,\"email\":\"...\"}}";
JsonObject injury = new JsonParser().parse(json).getAsJsonObject();
JsonObject athelete = new JsonParser().parse(injury.get("athlete").toString()).getAsJsonObject();
String updateJson = injury.toString().replace(injury.get("athlete").toString(), athelete.get("id").toString());
updateJson = updateJson.replace("athlete", "athleteId");
System.out.println(updateJson);
}
output:
{"id":123,"kindOfInjury":"...","muscle":"...","side":"...","outOfTrainig":"Y","injuryDate":"2018-Jun-02","athleteId":456}
Dependency:
implementation 'com.google.code.gson:gson:2.8.5'
If you can replace with regex that will be bit more cleaner.

Java object not populated from json request for inner class

Have searched in different sites but couldn't find correct answer, hence posting this request though it could possible duplicates.sorry for that.
I am sending the below json request to my back-end service and converting to java object for processing. I can see the request body passed to my service but when i convert from json to java object , values are not populating
{
"data":{
"username":"martin",
"customerId":1234567890,
"firstName":"john",
"lastName":"smith",
"password":"p#ssrr0rd##12",
"email":"john.smith#gmail.com",
"contactNumber":"0342323443",
"department":"sports",
"location":"texas",
"status":"unlocked",
"OrderConfigs":[
{
"vpnId":"N4234554R",
"serviceId":"connectNow",
"serviceType":"WRLIP",
"ipAddress":"10.101.10.3",
"fRoute":[
"10.255.253.0/30",
" 10.255.254.0/30"
],
"timeout":1800,
"mapId":"test_map"
}
]
}
}
My Parser class have something like,
JSONObject requestJSON = new JSONObject(requestBody).getJSONObject("data");
ObjectMapper mapper = new ObjectMapper();
final String jsonData = requestJSON.toString();
OrderDTO mappedObject= mapper.readValue(jsonData , OrderDTO .class);
// I can see value coming from front-end but not populating in the mappedObject
My OrderDTO.java
#JsonInclude(value = Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true,value = {"hibernateLazyInitializer", "handler", "created"})
public class OrderDTO {
private String username;
private long customerId;
private String source;
private String firstName;
private String lastName;
private String email;
private String contactNumber;
private String password;
private String department;
private String location;
private String status;
private List<OrderConfig> OrderConfigs;
#JsonInclude(value = Include.NON_NULL)
public class OrderConfig {
private String vpnId;
private String serviceId;
private String serviceType;
private String ipAddress;
private String mapId;
private String[] fRoutes;
private Map<String, Object> attributes;
private SubConfig subConfig;
private String routeFlag;
getter/setters
.....
}
all setter/getter
}
Not sure what I'm missing here. Is this right way to do?
If your are trying to use inner class, correct way to use is to declare it static for Jackson to work with inner classes.
For reference check this
code changes made are
#JsonInclude(value = Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
static class OrderConfig {
Make sure that your json tag names match with variable names of java object
Ex : "fRoute":[
"10.255.253.0/30",
" 10.255.254.0/30"
],
private String[] fRoutes;
OrderConfigs fields will not be initialized, just modify your bean as
#JsonProperty("OrderConfigs")
private List<OrderConfig> orderConfigs;
// setter and getter as setOrderConfigs / getOrderConfigs
See my answer here. (same issue)

Jackson - Deserialize empty String Member to null

I like to deserialize with Jackson an empty String member ("") to null. The Deserialization Feature "ACCEPT_EMPTY_STRING_AS_NULL_OBJECT" can for this unfortunately not be used (see link).
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonInclude(Include.NON_NULL)
public class Supplier {
private Integer id;
private String name;
private String image;
private String link;
private String description;
}
So after deserialization of the following JSON String the string members "link" and "image" should be null and not "".
{"id":37,"name":"Life","image":"","link":"","description":null}
I am looking for a way to write an own deserializer which can be used for String members of a POJO. Is there a way to achieve this? I am using faster Jackson 2.6.0.
The custom deserializer can be done as follows in Jackson 2.6.0.
public class SupplierDeserializer extends JsonDeserializer<Supplier> {
#Override
public Supplier deserialize(JsonParser jp, DeserializationContext context) throws IOException, JsonProcessingException {
Supplier sup = new Supplier();
JsonNode node = jp.readValueAsTree();
sup.setId(node.get("id").asInt());
sup.setDescription(node.get("description").asText());
String image = node.get("image").asText();
if("".equals(image)) {
image = null;
}
sup.setImage(image);
String link = node.get("link").asText();
if("".equals(link)) {
link = null;
}
sup.setLink(link);
sup.setName(node.get("name").asText());
return sup;
}
}
Register the custom deserialiser with the Supplier class
#JsonDeserialize(using = SupplierDeserializer.class)
public class Supplier {
private Integer id;
private String name;
private String image;
private String link;
private String description;
// getters and setters
}
Call the ObjectMapper class to parse the JSON data
String jsonData = "{\"id\":37,\"name\":\"Life\",\"image\":\"\",\"link\":\"\",\"description\":null}";
Supplier sup = new ObjectMapper().readValue(jsonData, Supplier.class);

Parsing JSON objects: Call the constructor after parsing?

I have the following POJO class for a JSON object:
public class JSONChangeSet {
public JSONChangeSet {
System.out.println("Owner: " + owner);
}
#SerializedName("comment")
private String comment;
#SerializedName("lastUpdatedDate")
private String modifiedDate;
#SerializedName("owner")
private Resource owner;
#SerializedName("modifiedBy")
private Resource modifier;
public String getComment() {
return comment;
}
}
Obviously this doesnt work, because the field owner has not yet a value assigned when the constructor is called. Is there any possibility to call a method automatically after the JSON object is parsed?
You tagged your question with gson, but I would recommend you the Jackson library instead, because I saw your last two questions, and seems like gson is not flexible enough for you.
In Jackson your example would look like this:
public final class JSONChangeSet {
private final String comment;
private final Resource owner;
#JsonCreator
public JSONChangeSet(
#JsonProperty("comment") final Resource owner,
#JsonProperty("comment") final String comment
) {
this.comment = comment;
this.owner = owner;
}
public String getComment() {
return comment;
}
}
With this solution you can have immutable objects, which will built by the constructor. It's also good for the DI pattern. And BTW Jackson is lightning fast.
You may want to read this question also.
I think Gson does not has a "listener" for that. You can try the following trick:
static class JSONChangeSet {
#SerializedName("comment")
private String comment;
#SerializedName("owner")
private int owner;
}
static class JSONChangeSetDeserializer implements JsonDeserializer<JSONChangeSet> {
Gson gson = new Gson();
#Override
public JSONChangeSet deserialize(final JsonElement json, final Type typeOfT,
final JsonDeserializationContext context) throws JsonParseException {
final JSONChangeSet obj = gson.fromJson(json, typeOfT);
// Code you want to run
System.out.println("Owner: " + obj.owner);
return obj;
}
}
public static void main(final String[] args) throws Exception, JsonMappingException, IOException {
final GsonBuilder gson = new GsonBuilder();
gson.registerTypeAdapter(JSONChangeSet.class, new JSONChangeSetDeserializer());
gson.create().fromJson("{\"comment\": \"it works!\", \"owner\": 23}", JSONChangeSet.class);
}

Categories