Use Gson to serialize complex set - java

I have a method, setFriends(), that takes a Set. This method is in another module and I want to send setFriends() serialized data via Gson().fromJson(). I am not sure if I have the arg string correct. I have tried the following which failed:
// my attempt to serialize
String arg = "[Friend[name=Dave, relationship=Relationship[Work]], Friend[name=Jack, relationship=Relationship[School]]]"; // not sure if this string is correct
Type type = new TypeToken<Set<Friend>>(){}.getType();
Set<Friend> payload = new Gson().fromJson(arg, type);
sendPayload(payload); // will send payload to People.setFriends()
// code from the other module:
Set<Friend>
public class People {
public void setFriends(Set<Friend> friends) { ... }
}
public class Friend {
String name;
Relationship relationship;
}
public enum Relationship {
School,
Work
}

Google Gson is a simple Java-based library to serialize Java objects to JSON and vice versa. In JSON we represent objects using {}. For nested objects we use "fieldName": {<nested object>}.
In your example I've considered relationship as an enum. And introduced Address as a nested object. JSON for the Friend object will look like this:
{
"name" : "Dave",
"relationship" : "WORK",
"address" : {"street" : "s1"}
}
There is no representation for Set structure in JSON so you put elements in list.Following is the sample java code:
public class Test
{
public static void main(String[] args)
{
String arg = "["
+ "{\"name\":\"Dave\",\"relationship\":\"WORK\",\"address\":{\"street\":\"s1\"}},"
+ "{\"name\":\"Jack\",\"relationship\":\"SCHOOL\",\"address\":{\"street\":\"s2\"}},"
+ "{\"name\":\"Dave\",\"relationship\":\"GYM\",\"address\":{\"street\":\"s3\"}}"
+ "]";
Type type = new TypeToken<Set<Friend>>(){}.getType();
Set<Friend> payload = new Gson().fromJson(arg, type);
sendPayload(payload);
}
static void sendPayload(Set<Friend> plod) {
System.out.println("Sent payload: " + plod.toString());
}
}
class Friend {
private String name;
private Relationship relationship;
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String getName() {
return name;
}
public Relationship getRelationship() {
return relationship;
}
public void setRelationship(Relationship relationship) {
this.relationship = relationship;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return this.name;
}
#Override
public int hashCode() {
return name.hashCode();
}
#Override
public boolean equals(Object obj) {
return name.equals(obj.toString());
}
}
enum Relationship {
WORK, SCHOOL, GYM
}
class Address {
String street;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
}
Output:
Sent payload: [Dave, Jack]
In my environment Gson returned LinkedHashSet object. If you want different set like sorted ones. Then you can deserialize the Json into List<Freind> then convert it to the desired set.

Related

Java how to update a JSON object value and send it as a body to PUT request

I am trying to automate my REST service's PUT request and I am completely new to JAva. Here I am passing a PUT body(in JSON format) along with other headers.
I had created a Java class for PUT in which I have getters and setters and I am assigning values using setter and creating my PUT body and sending this PUT body in my PUT request.
My PUT body is something like this . I am able to update "id" and "name" and create my body object but I am not sure how do I update the "versionname" and"number" under "versions" path?
{
"versions": [
{
"versionname": "Test",
"number": 1
}
],
"id": 89960004,
"name": "TEST CES LIST4",
}
The class for PUT body is as below:
public class putBody {
public String id;
public String name;
public String versionName;
public String number;
public String getId() {
return id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String getversionName() {
return versionName;
}
public void setversionName(String versionName) {
this.versionName = versionName;
}
My question is how to update the "versionname" and "number" and create my putBody object. Any help much appreciated.
First, your PutBody class must have a collection to keep your version data, according to the JSON output that you provided.
For this purpose, just create a Version class that will be used for every single version information:
public class Version {
public String versionName;
public String number;
public String getVersionName() {
return versionName;
}
public void setVersionName(String versionName) {
this.versionName = versionName;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
Then, here is your PutBody class should be look like
public class PutBody {
public String id;
public String name;
public List<Version> versions;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Version> getVersions() {
return versions;
}
public void setVersions(List<Version> versions) {
this.versions = versions;
}
}
And here is how to fill it with data according to your example values :
List<Version> versions = new ArrayList<Version>();
Version version = new Version();
version.setVersionName("Test");
version.setNumber("1");
versions.add(version);
PutBody putBody = new PutBody();
putBody.setName("TEST CES LIST4");
putBody.setId("89960004");
putBody.setVersions(versions);
And the JSON Output :
{
"id": "89960004",
"name": "TEST CES LIST4",
"versions": [
{
"versionName": "Test",
"number": "1"
}
]
}
UPDATE
Google's Gson has great features for this purpose. You can easily convert Java instances to JSON and convert JSON strings back to Java instances.
Please check that

Android Retrofit - How to seperate classes from JSON Array

trying to access JSON data from the following:
{"actions":[{"actionType":0,"email":"contact#tonyspizza.com","faIcon":"fa-envelope",
"name":"Contact Us","subject":"Email from Tony's Pizza App"},
{"actionType":2,"faIcon":"fa-phone","name":"Call Us","number":"5204558897"}],
"total":2}
I'm trying to use retrofit to access the 'actions' as each individual classes. (i.e. ActionEmail, ActionPhone, etc). I cannot figure out a way to separate these into separate classes and not have one class with all the properties.
Thanks in advance!
Call<ActionWrapperObject> getActions(// Put your api call body in there);
Here is your ActionWrapperObject
public class ActionWrapperObject {
ArrayList<ActionModel> actions;
public ArrayList<ActionModel> getActions() {
return actions;
}
public void setActions(ArrayList<ActionModel> actions) {
this.actions = actions;
}
}
Here is your ActionModel
public class ActionModel {
int actionType;
String email;
String faIcon;
String name;
String subject;
public int getActionType() {
return actionType;
}
public void setActionType(int actionType) {
this.actionType = actionType;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getFaIcon() {
return faIcon;
}
public void setFaIcon(String faIcon) {
this.faIcon = faIcon;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
}
You in your response
Your api call.enqueue(new Callback<ActionWrapperObject>() {
#Override
public void onResponse(Call<ActionWrapperObject> call, Response<ActionWrapperObject> response) {
ActionWrapperObject actionWrapperObj= response.body();
if (actionWrapperObj!= null) {
ArrayList<ActionModel> actionModelList= actionWrapperObj.getActions();
//Here you got the list of actions. Do what ever you want with them. You can
// differentiate each action on its type.
}
}
What I infer is you want to generate fields of the ActionModel class dynamically. You can refer to generating JSON pojo dynamically using reflection.

Deserialize an object's property which has an inconsistent name?

Using Retrofit here to consume Google Civic API.
The library requires you to create a model of what the API will return as I have done already with Election. Which is basically a copy of the google documentation.
(Retrofit binds the response properties to properties with the same name)
Election.Java :
public class Election {
private long id;
private String name;
private String electionDay;
private String ocdDivisionId;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getElectionDay() {
return electionDay;
}
public void setElectionDay(String electionDay) {
this.electionDay = electionDay;
}
public String getOcdDivisionId() {
return ocdDivisionId;
}
public void setOcdDivisionId(String ocdDivisionId) {
this.ocdDivisionId = ocdDivisionId;
}
}
But Representatives have an inconsistent property name, thus I don't see a way to model this in a way Retrofit will know how to deserialize the API's response.
Representatives object (JSON) :
property name is called (key)
How do I let Retrofit deserialize a model that captures the property named variable after a key of the division?
Assuming you're using a Gson converter, I personally would use a map. I guess the same can be achieved with other converters, but I never used them. Say you have the following object:
public class Division {
#SerializedName("name")
#Expose
private String name;
#SerializedName("alsoKnownAs")
#Expose
private List<String> alsoKnownAs = new ArrayList<>();
#SerializedName("officeIndices")
#Expose
private List<Integer> officeIndices = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getAlsoKnownAs() {
return alsoKnownAs;
}
public void setAlsoKnownAs(List<String> alsoKnownAs) {
this.alsoKnownAs = alsoKnownAs;
}
public List<Integer> getOfficeIndices() {
return officeIndices;
}
public void setOfficeIndices(List<Integer> officeIndices) {
this.officeIndices = officeIndices;
}
}
Which represents the object inside the divisions array. You can then have the class:
private class Divisions {
#SerializedName("divisions")
#Expose
private Map<String, Division> divisions = new HashMap<>();
// ...
}
Notice the usage of a map here? Behind the scenes Gson will be able to serialise and deserialise your objects. The class Divisions is the root of the json you gave us in the question.
Hope this helps

JSON - Error on putting a JSON string inside a JSON object

I have a web-service in Java with Jersey to create and edit prices of a market. To do that, I send a JSON object containing the market informations, including another JSON object for the prices.
For example, this is the JSON I'm posting through Postman:
{
"name": "Market 01",
"address": "Market 01 street",
"prices": "{\"watermelon\": \"5.40\", \"melon\": \"2.55\"}"
}
On the web-server side, I try to create a list of the prices using GSON, but I can't get it to work. My objective here is to check on the difference between the new prices and the current prices. Below, there is my POJO Price.java, what I'm trying to do on the Controller for the edit and the Exception I'm geting on Postman:
POJO - Price.java
public class Price {
private String nome;
private Double preco;
//Getters and setters also
}
MarketController.java
Collection<Price> prices = gson.fromJson(json, new TypeToken<List<Price>>(){}.getType());
Exception raised on MarketController.java:
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
EDIT: The solution that worked for me based on #A2H response:
POJO class - Price.java
public class Price {
private String name;
private Double price;
...
#Override
public String toString() {
return "{\"name\":\"" + name + "\", \"price\":" + price + "}";
}
}
POJO class - Market.java
public class Market{
...
//Include as a List<Price>
private List<Price> prices;
...
}
MarketController.java
// When going from List<Price> to JSON String
String prices = gson.toJson(market.getPrices());
// When going from JSON String to List<Price>
List<Price> prices = gson.fromJson(jsonString, new TypeToken<List<Price>>(){}.getType());
This code is well rounded for this situation, where you need to transform from List to JSON String and vice-versa.
Your POJO implies that you should have an array of prices in your JSON object.
Here's a full working example.
package test;
import java.util.List;
import com.google.gson.Gson;
public class TESTTEST {
public class MarketInfo {
String name;
String address;
List<Price> prices;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List<Price> getPrices() {
return prices;
}
public void setPrices(List<Price> prices) {
this.prices = prices;
}
}
public class Price {
String nome;
Double preco;
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public Double getPreco() {
return preco;
}
public void setPreco(Double preco) {
this.preco = preco;
}
#Override
public String toString() {
return "{\"nome\":\"" + nome + "\", \"preco\":" + preco + "}";
}
}
public static void main(String[] args) {
Gson gson = new Gson();
String jsonString = "{\"name\": \"Market 01\",\"address\": \"Market 01 street\","
+ "\"prices\": [{\"nome\":\"watermelon\",\"preco\":\"5.40\"}, {\"nome\":\"melon\",\"preco\": \"2.55\"}]}";
MarketInfo res = gson.fromJson(jsonString, MarketInfo.class);
System.out.println(res.getPrices());
}
}
That's because a List would be represented by a JSON array, not by an object as you provide. You can try to deserialize to a map (or, send an array).

Convert Object to String

I have a couple to class in which I'm getting and setting a few things and then finally calling it in my main method. But when I call my class in the main method it just gives me the object instead of name,address and age. I know this structure is very complicated but I want to keep this structure because later on I will be adding a lot of things to this. It would be AMAZING if someone could tell me how to do this. I would really appreciate this. Below is my code for all my classes
This is my first class
public class methodOne
{
public String getName()
{
String name = "UserOne";
return name;
}
public int getAge()
{
int age = 17;
return age;
}
public String getAddress()
{
String address = "United States";
return address;
}
}
This is my second class
public class methodTwo
{
String name;
String address;
int age;
public methodTwo(methodOne objectOne)
{
name=objectOne.getName();
address=objectOne.getAddress();
age=objectOne.getAge();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
This is my third class
public class methodThree {
private methodTwo methodTwoInMethodThree;
private methodOne methodOneInMethodThree;
public methodThree()
{
this.methodOneInMethodThree = new methodOne();
this.methodTwoInMethodThree = new methodTwo(methodOneInMethodThree);
}
public methodTwo getMethodTwoInMethodThree() {
return methodTwoInMethodThree;
}
public void setMethodTwoInMethodThree(methodTwo methodTwoInMethodThree) {
this.methodTwoInMethodThree = methodTwoInMethodThree;
}
}
This is my fourth class which is the method maker
public class methodMaker {
public methodThree brandNewFunction(methodTwo object)
{
methodThree thirdMethod = new methodThree();
thirdMethod.setMethodTwoInMethodThree(object);
return thirdMethod;
}
}
This is my main class which calls methodMaker. What I want to achieve is that when I print the value it should print the name,address and age but instead it just prints trial.methodThree#4de5ed7b
public class mainClass {
public static void main(String args[])
{
methodMaker makerOfMethods = new methodMaker();
methodOne one = new methodOne();
methodTwo object = new methodTwo(one);
System.out.println(makerOfMethods.brandNewFunction(object).toString());
}
}
What you need to do is to override the default implementation of the .toString() method in the objects you want to print out:
#Override
public String toString()
{
return "Name: " + this.name;
}
EDIT:
I do not know exactly where you are printing, and you naming convention doesn't really help out, but from what I am understanding, you would need to implement it in all of you classes since they all seem to be related to each other.
So, in your methodOne class (can also be applied to methodTwo):
#Override
public String toString()
{
return "Name: " + this.name + " Age: " + this.age + " Address: + " this.address;
}
In your methodThree class:
private methodTwo methodTwoInMethodThree;
private methodOne methodOneInMethodThree;
#Override
public String toString()
{
StringBulder sb = new StringBuilder();
if(this.methodTwoInMethodThree != null)
{
sb.append("Method 2:").append(methodTwoInMethodThree.toString());
}
if(methodOneInMethodThree != null)
{
sb.append("Method 1:").append(methodOneInMethodThree.toString());
}
return sb.toString();
}
When you call
MyClass myObject = new MyClass();
System.out.println(myObject);
Implicitly , java calls instead
System.out.println(myObject.toString());
So, if in MyClass, you override toString(), then whatever your toString method returns is what's gonna be printed.
Side note: are you confusing classes and methods? Methods are functions in your classes, classes are wrappers around a bunch of attributes and methods. Your naming is confusing.
try this code:
public class methodTwo
{
String name;
String address;
int age;
public methodTwo(methodOne objectOne)
{
name=objectOne.getName();
address=objectOne.getAddress();
age=objectOne.getAge();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString(){
return name+" "+address+" "+age;
}
}
Are you printing the object using println()?
From the docs, println():
calls at first String.valueOf(x) to get the printed object's string value
This string value is obtained from the object's toString() method, which:
returns a string consisting of the name of the class of which the object is an instance, the at-sign character `#', and the unsigned hexadecimal representation of the hash code of the object
So if you want to print anything other than this you have to override the toString() method in your object and return a string containing whatever you want.
Just google "override tostring java" and you will see a ton of examples.

Categories