I have a generic Java Message object that's represented by the following json string:
{
"type": "Example",
"processTime": 3.4,
"payload":
{
"id": "someString",
"type": "anotherString",
"message": "yetAnotherString"
}
}
The Java Message object is generic. I also have an object called Event. When trying to convert the json into a Message<Event> object using gson, a Message object is returned with the correct json values, but the nested generic object is somehow returned as a "LinkedTreeMap" object instead of an Event object. I know this has something to do with type erasure, but I still can't seem to figure out how to return a Message<Event> from the json.
This is my main():
public class App {
public static void main(String[] args) {
//The json string to convert into a "Message<Event>" object
String jsonString = "{\"type\":\"Example\",\"processTime\":3.4,\"payload\":{\"id\":\"someString\",\"type\":\"anotherString\",\"message\":\"yetAnotherString\"}}";
Message<Event> message = new Message<Event>();
message = message.convertJsonToObject(jsonString, Event.class);
System.out.println(message.getClass().getName()); //returns as a "Message" class -- as expected
System.out.println(message.getPayload().getClass().getName()); //returns as a "LinkedTreeMap" instead of an "Event" object
}
}
Message class:
public class Message<T> {
private String type;
private double processTime;
private T payload;
public Message(String type, double processTime, T payload) {
this.type = type;
this.processTime = processTime;
this.payload = payload;
}
public Message() {
type = null;
processTime = 0;
payload = null;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public double getProcessTime() {
return processTime;
}
public void setProcessTime(double processTime) {
this.processTime = processTime;
}
public T getPayload() {
return payload;
}
public void setPayload(T payload) {
this.payload = payload;
}
public Message<T> convertJsonToObject(String jsonString, Class<T> classType) {
GsonBuilder gson = new GsonBuilder();
Type collectionType = new TypeToken<Message<T>>() {}.getType();
Message<T> myMessage = gson.create().fromJson(jsonString, collectionType);
return myMessage;
}
#Override
public String toString() {
return new Gson().toJson(this);
}
}
Event class:
public class Event {
private String id;
private String type;
private String message;
public Event(String id, String type, String message) {
this.id = id;
this.type = type;
this.message = message;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
#Override
public String toString() {
return new Gson().toJson(this);
}
}
Related
I have a sqs queue , I am polling for messages .
I get the message in following format
{
"Type" : "type_value",
"MessageId" : "message_id",
"TopicArn" : "topic_arn",
"Message" : "{\n \"contentType\": \"content_type_value\",\n \"content\": \"content_value\",\n \"eventName\": \"event_name\",\n \"eventTS\": 1591235390353\n}",
"Timestamp" : "2020-06-04T01:49:50.358Z",
"SignatureVersion" : "1",
"UnsubscribeURL" : "url"
}
when I get this body from SQS using code
String message = sqs_message_object.getBody()
Now I create a wrapper class for thie message body as following
public class SQSMessage
{
#JsonProperty("Type")
private String type;
#JsonProperty("MessageId")
private String messageId;
#JsonProperty("TopicArn")
private String topicArn;
#JsonProperty("Message")
private Message message;
#JsonProperty("Timestamp")
private String timestamp;
#JsonProperty("SignatureVersion")
private int signatureVersion;
#JsonProperty("UnsubscribeURL")
private String unSubscribeUrl;
public String getType()
{
return type;
}
public void setType(String type)
{
this.type = type;
}
public String getMessageId()
{
return messageId;
}
public void setMessageId(String messageId)
{
this.messageId = messageId;
}
public String getTopicArn()
{
return topicArn;
}
public void setTopicArn(String topicArn)
{
this.topicArn = topicArn;
}
public Message getMessage()
{
return message;
}
public void setMessage(Message message)
{
this.message = message;
}
public String getTimestamp()
{
return timestamp;
}
public void setTimestamp(String timestamp)
{
this.timestamp = timestamp;
}
public int getSignatureVersion()
{
return signatureVersion;
}
public void setSignatureVersion(int signatureVersion)
{
this.signatureVersion = signatureVersion;
}
public String getUnSubscribeUrl()
{
return unSubscribeUrl;
}
public void setUnSubscribeUrl(String unSubscribeUrl)
{
this.unSubscribeUrl = unSubscribeUrl;
}
}
And I deserialize the json string in to a SQSMessage object using Object Mapper
SQSMessage sqsMessage = null;
try
{
sqsMessage = objectMapper.readValue(message,SQSMessage.class);
}
catch(JsonProcessingException e2)
{
}
all the fields are getting mapped except for Message field .
because its not just a string but another class.
public class Message
{
private String contentType;
private Content content;
private String eventName;
private Date eventTS;
public String getContentType()
{
return contentType;
}
public void setContentType(String contentType)
{
this.contentType = contentType;
}
public Content getContent()
{
return content;
}
public void setContent(Content content)
{
this.content = content;
}
public String getEventName()
{
return eventName;
}
public void setEventName(String eventName)
{
this.eventName = eventName;
}
public Date getEventTS()
{
return eventTS;
}
public void setEventTS(Date eventTS)
{
this.eventTS = eventTS;
}
}
it fils to deserialize the field Message .
how do i Map the message field to Messaeg class as mentioned.
The error I get is
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `domain.Message`
(although at least one Creator exists): no String-argument constructor/factory method to deserialize
from String value ('{\n \"contentType\": \"content_type_value\",\n \"content\": \"content_value\",\n \"eventName\": \"event_name\",\n \"eventTS\": 1591235390353\n}')
at [Source: (String)"{
I'm using retrofit2 and Rxjava2 to insert/get information from mongodb and nodeJs server, for now, I receive all data as a string but I want to get hole collection Infos from my base so I need to convert string to JSON and get each information.
My code to receive data:
1- Service:
#POST("collect/get")
#FormUrlEncoded
Observable<String> getcollection(#Field("selector") String selector);
2-RetrofitClient:
if(instance == null){
instance = new Retrofit.Builder()
.baseUrl("http://transportor.ddns.net:3000/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(ScalarsConverterFactory.create()).build();
}
3- Recieve function
private void getallcollection(String selector) {
compositeDisposable.add(myServices.getcollection(selector)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>(){
#Override
public void accept(String s) throws Exception {
Log.d("infos",s);
}
}));
}
I'm already prepared Collection class:
public class col {
private String creator;
private String emailcol;
private String date_creation_col;
private String nom_col;
private String long_col;
private String lat_col;
private String tel_fix_col;
private String tel_mobile_col;
private String creatorcreator;
private String heure_matin_col;
private String heure_apresmatin_col;
private String type;
private String imagePath;
public col(String creator, String emailcol, String date_creation_col, String nom_col, String long_col, String lat_col, String tel_fix_col, String tel_mobile_col, String creatorcreator, String heure_matin_col, String heure_apresmatin_col, String type, String imagePath) {
this.creator = creator;
this.emailcol = emailcol;
this.date_creation_col = date_creation_col;
this.nom_col = nom_col;
this.long_col = long_col;
this.lat_col = lat_col;
this.tel_fix_col = tel_fix_col;
this.tel_mobile_col = tel_mobile_col;
this.creatorcreator = creatorcreator;
this.heure_matin_col = heure_matin_col;
this.heure_apresmatin_col = heure_apresmatin_col;
this.type = type;
this.imagePath = imagePath;
}
public String getCreator() {
return creator;
}
public void setCreator(String creator) {
this.creator = creator;
}
public String getEmailcol() {
return emailcol;
}
public void setEmailcol(String emailcol) {
this.emailcol = emailcol;
}
public String getDate_creation_col() {
return date_creation_col;
}
public void setDate_creation_col(String date_creation_col) {
this.date_creation_col = date_creation_col;
}
public String getNom_col() {
return nom_col;
}
public void setNom_col(String nom_col) {
this.nom_col = nom_col;
}
public String getLong_col() {
return long_col;
}
public void setLong_col(String long_col) {
this.long_col = long_col;
}
public String getLat_col() {
return lat_col;
}
public void setLat_col(String lat_col) {
this.lat_col = lat_col;
}
public String getTel_fix_col() {
return tel_fix_col;
}
public void setTel_fix_col(String tel_fix_col) {
this.tel_fix_col = tel_fix_col;
}
public String getTel_mobile_col() {
return tel_mobile_col;
}
public void setTel_mobile_col(String tel_mobile_col) {
this.tel_mobile_col = tel_mobile_col;
}
public String getCreatorcreator() {
return creatorcreator;
}
public void setCreatorcreator(String creatorcreator) {
this.creatorcreator = creatorcreator;
}
public String getHeure_matin_col() {
return heure_matin_col;
}
public void setHeure_matin_col(String heure_matin_col) {
this.heure_matin_col = heure_matin_col;
}
public String getHeure_apresmatin_col() {
return heure_apresmatin_col;
}
public void setHeure_apresmatin_col(String heure_apresmatin_col) {
this.heure_apresmatin_col = heure_apresmatin_col;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getImagePath() {
return imagePath;
}
public void setImagePath(String imagePath) {
this.imagePath = imagePath;
}
}
Actually I received all data and console show me : [{"_id":"5e22074673c926147c3a73f5","date_creation_col":"17-01-2020","creator":"Alaeddine","emailcol":"amir#gmail.com","nom_col":"amir","long_col":"10.179326869547367","lat_col":"36.83353893150942","tel_fix_col":"123","tel_mobile_col":"1234","adress_col":"rue Paris mision 34","heure_matin_col":"7","heure_apresmatin_col":"5","type":"collection","imagePath":"mmmmmmmmmmmm"}]
I want to know how to extract for example creator from this Json.
You can use a third-party JSON parser, like Google GSON, as you're already developing for Android. Java does not seem to contain a built-in JSON parser.
See this answer.
My Api response looks like this.
{
"status" : 1,
"message" : "Some Message",
"data" : {
}
}
My Response class looks like this. The type of data changes depending on the request being made.
public class Response<T>{
#Expose
#SerializedName("status")
private Integer status;
#Expose
#SerializedName("message")
private String message;
#Expose
#SerializedName("data")
private T data;
//Getters and Setters
}
Question 1. How to use gson to parse this json?
Response<ClassA> response = new Gson().fromJson(jsonString, ??);
Question 2. How would i write Parcelable implementation for this class.
dest.writeInt(status == null ? 0:status);
dest.writeString(message);
??
You need to do some changes in your Model structure. To do this..
Create a BaseDTO which is nothing but your Response class and extend your BaseDTO with your ClassA.
BaseDto.class
public class BaseDto {
#Expose
#SerializedName("status")
protected Integer status;
#Expose
#SerializedName("message")
protected String message;
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
ClassA.class
public class ClassA extends BaseDto implements Parcelable {
String name;
protected ClassA(Parcel in) {
name = in.readString();
status = in.readByte() == 0x00 ? null : in.readInt();
message = in.readString();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
if (status == null) {
dest.writeByte((byte) (0x00));
} else {
dest.writeByte((byte) (0x01));
dest.writeInt(status);
}
dest.writeString(message);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<ClassA> CREATOR = new Parcelable.Creator<ClassA>() {
#Override
public ClassA createFromParcel(Parcel in) {
return new ClassA(in);
}
#Override
public ClassA[] newArray(int size) {
return new ClassA[size];
}
};
}
Use this site to generate Parcelable class http://www.parcelabler.com/
to parse using gson you just need to pass it's type to it..
I have written a function to simplify this..
Save these in a Util class
public static <T> String convertObjectToStringJson(T someObject, Type type) {
Gson gson = new Gson();
String strJson = gson.toJson(someObject, type);
return strJson;
}
public static <T> T getObjectFromJson(String json, Type type) {
Gson gson = new Gson();
if (json != null) {
if (json.isEmpty()) {
return null;
}
}
return gson.fromJson(json, type);
}
example to use these function:
ClassA classA = Util.getObjectFromJson(strJson, new TypeToken<ClassA>() {}.getType());
String jsonClassA = Util.convertObjectToStringJson(objClassA, new TypeToken<ClassA>() {}.getType());
Answering my own question.
Question 1:
Response<ClassA> response = new Gson().fromJson(jsonString, new TypeToken<Response<ClassA>>(){}.getType());
Question 2:
Changed class to this.
public class Response<T extends Parcelable>{
#Expose
#SerializedName("status")
private Integer status;
#Expose
#SerializedName("message")
private String message;
#Expose
#SerializedName("data")
private T data;
//Getters and Setters
#Override
public void writeToParcel(Parcel dest, int flags) {
if (data != null) {
dest.writeString(data.getClass().getName());
dest.writeParcelable(data, flags);
} else dest.writeString(null);
dest.writeString(message);
dest.writeInt(status);
}
}
protected Response(Parcel in) {
String className = in.readString();
if (className != null) {
try {
data = in.readParcelable(Class.forName(className).getClassLoader());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
message = in.readString();
status = in.readInt();
}
Given I have the following json:
{
"Company": {
"name": "cookieltd",
"type": "food",
"franchise_location": [
{
"location_type": "town",
"address_1": "5street"
},
{
"location_type": "village",
"address_1": "2road"
}
]
}
}
How can it be binded to the following object classes using Jackson?:
1) Company class
public class Company
{
String name, type;
List<Location> franchise_location = new ArrayList<Location>();
[getters and setters]
}
2) Location class
public class Location
{
String location_type, address_1;
[getters and setters]
}
I have done:
String content = [json above];
ObjectReader reader = mapper.reader(Company.class).withRootName("Company"); //read after the root name
Company company = reader.readValue(content);
but I am getting:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "franchise_location"
As far as I can tell, you are simply missing an appropriately named getter for the field franchise_location. It should be
public List<Location> getFranchise_location() {
return franchise_location;
}
(and the setter)
public void setFranchise_location(List<Location> franchise_location) {
this.franchise_location = franchise_location;
}
Alternatively, you can annotate your current getter or field with
#JsonProperty("franchise_location")
private List<Location> franchiseLocation = ...;
which helps to map JSON element names that don't really work with Java field name conventions.
The following works for me
public static void main(String[] args) throws Exception {
String json = "{ \"Company\": { \"name\": \"cookieltd\", \"type\": \"food\", \"franchise_location\": [ { \"location_type\": \"town\", \"address_1\": \"5street\" }, { \"location_type\": \"village\", \"address_1\": \"2road\" } ] } }";
ObjectMapper mapper = new ObjectMapper();
ObjectReader reader = mapper.reader(Company.class).withRootName(
"Company"); // read after the root name
Company company = reader.readValue(json);
System.out.println(company.getFranchise_location().get(0).getAddress_1());
}
public static class Company {
private String name;
private String type;
private List<Location> franchise_location = new ArrayList<Location>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<Location> getFranchise_location() {
return franchise_location;
}
public void setFranchise_location(List<Location> franchise_location) {
this.franchise_location = franchise_location;
}
}
public static class Location {
private String location_type;
private String address_1;
public String getLocation_type() {
return location_type;
}
public void setLocation_type(String location_type) {
this.location_type = location_type;
}
public String getAddress_1() {
return address_1;
}
public void setAddress_1(String address_1) {
this.address_1 = address_1;
}
}
and prints
5street
my solution for JSON is always GSON, you can do some research on that, as long as you have the correct structure of class according to the JSON, it can automatically transfer from JSON to object:
Company company = gson.fromJson(json, Company.class);
GSON is so smart to do the convertion thing!
enjoy GSON !
I am working on facebook application. When i queried for https://graph.facebook.com/me/video.watches?offset=0&limit=1000 I am getting a List of Watched Movies. For eg. I am pasting only one movie out of that list here.
{
"data": [
{
"id": "664878940211923",
"data": {
"tv_show": {
"id": "108611845829948",
"url": "https://www.facebook.com/pages/Popeye-the-Sailor/108611845829948",
"type": "video.tv_show",
"title": "Popeye the Sailor"
}
},
"type": "video.watches",
},
Here is the POJO Class I created to convert this to Java.
import java.util.List;
public class FBUserVideoWatches {
private List<Data> data;
public List<Data> getData() {
return data;
}
public void setData(List<Data> data) {
this.data = data;
}
public class Data{
private long id;
private TVData data;
private String type;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public TVData getData() {
return data;
}
public void setData(TVData data) {
this.data = data;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
public class TVData{
private TV_Shows tv_shows;
public TV_Shows getTv_shows() {
return tv_shows;
}
public void setTv_shows(TV_Shows tv_shows) {
this.tv_shows = tv_shows;
}
}
public class TV_Shows{
private long id;
private String url;
private String type;
private String title;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
}
Here is how i convert the json to java.
FBUserVideoWatches fbUserVideoWatches = gson.fromJson(response.getBody(), FBUserVideoWatches.class);
for (Data data : fbUserVideoWatches.getData()) {
System.out.println(data.getId());//This only works and I am getting values.
if(null != data.getData()){
if(null!=data.getData().getTv_shows()){
System.out.print(data.getData().getTv_shows().getTitle());
}
if(null!=data.getData().getTv_shows()){
System.out.print(data.getData().getTv_shows().getType());
}
}
}
When I use getter methods to get data from java class I am getting ID 664878940211923 & "type": "video.watches" as shown above. The members inside "tv_show" I am unable to access. I think some where I went wrong in creating POJO. I am unable to find that mistake. Please help me what corrections is necessary to make that work. Hope my question is clear. Thanks in Advance.
You were doing mistake in TVData Class your forgot serialized name on instance property coz its in diffferent in json and TV data class
#SerializedName(value="tv_show")
private TV_Shows tv_shows;
Assuming your json is like this
{
"data":[
{
"id":"664878940211923",
"data":{
"tv_show":{
"id":"108611845829948",
"url":"https://www.facebook.com/pages/Popeye-the-Sailor/108611845829948",
"type":"video.tv_show",
"title":"Popeye the Sailor"
}
},
"type":"video.watches"
},
{
"id":"664878940211923",
"data":{
"tv_show":{
"id":"108611845829948",
"url":"https://www.facebook.com/pages/Popeye-the-Sailor/108611845829948",
"type":"video.tv_show",
"title":"Popeye the Sailor"
}
},
"type":"video.watches"
}
]
}
Parsing model will like below according you to your json format
public class FBUserVideoWatches {
private List<Data> data;
public List<Data> getData() { return data; }
public void setData(List<Data> data) { this.data = data;}
}
public class Data {
private TVData data;
private String id;
private String type;
// setter/getter here
}
public class TVData {
#SerializedName(value="tv_show")
private Show show;
// setter/getter here
}
public class Show {
private String id;
private String url;
private String type;
private String title;
// setter/getter here
}
finally with Google Gson parse your object as like below
Gson gson = new Gson();
FBUserVideoWatches fbUserVideoWatches =gson.fromJson(json_string, FBUserVideoWatches.class);