How to write java classes representing json object with subobjects? - java

{
"car" : {
"color" : "red",
"year" : "2015",
"Activities" : [
{"activeDate" : "2019", "drivenBy" : "Jimmy"},
{"activeDate" : "2018", "drivenBy" : "Sam"}
],
"maker" : "GM"
}
}
I would like to write Java Class that represents the above JSON object to use it on my rest API request. I would appreciate your help.

Everything inside a pair of curly brackets can be seen as a java object. If you have square brackets then that means that you have a list and the simple properties are basic objects like strings, ints and so on.
So, for example:
{
"house" : {
"noRooms" : 3,
"rooms" : [
{"name" : "kitchen", "surface" : 10.5 },
{"name" : "bathroom", "surface" : 5 },
{"name" : "bedroom", "surface" : 12.3 }
]
}
}
In this, because you start with a pair of curly brackets you have your first object, which you can name whatever you want. For lack of a better name, I'll call mine Building.
Inside this building I have a property named house. Because this is specified by curly brackets it means we will need another object. We'll call this House.
Going deeper we see two properties of House: the number of rooms called noRooms and something called rooms which appears to be a list (notice the square brackets).
For the number of rooms, we don't need to create a different object as most frameworks/utilities know how to deal with this so, an integer will do just fine. For the things inside the list we will need special objects that we will call Room.
These objects have two properties, a name which translates into a string and a surface which could be a double.
So, your classes would look something like:
public class Building {
private House house;
//rest of the code
}
public class House {
private int noRooms;
private List<Room> rooms;
//rest of the code
}
public class Room {
private String name;
private double surface;
//rest of the code
}

Assuming that you're using Jackson as your serializer, you'll be needing three classes to perform the serialization/deserialization based on the example JSON object you provided:
public class ActivityResource {
private String activeDate;
public String getActiveDate() { return activeDate; }
public void setActiveDate(String activeDate) { this.activeDate = activeDate; }
private String drivenBy;
public String getDrivenBy() { return drivenBy; }
public void setDrivenBy(String drivenBy) { this.drivenBy = drivenBy; }
}
Followed by this:
public class CarResource {
private String color;
public String getColor() { return color; }
public void setColor(String color) { this.color = color; }
private String year;
public String getYear() { return year; }
public void setYear(String year) { this.year = year; }
#JsonProperty("Activities")
private List<ActivityResource> activities;
public List<ActivityResource> getActivities() { return activities; }
public void setActivities(List<ActivityResource> activities) { this.activities = activities; }
private String maker;
public String getMaker() { return maker; }
public void setMaker(String maker) { this.maker = maker; }
}
And finally this:
public class CarRequestResource {
private CarResource car;
public CarResource getCar() { return car; }
public void setCar(CarResource car) { this.car = car; }
}
With all these in place you'll be able to deserialize the request with no problems.

Based on the json you've posted, we're going to call the Java class Car.
Car has four attributes: color, year, activities, and maker.
You can simply find the datatype of each attribute by reviewing the json file. In this case, we have color, year and maker fields as strings and the activities is a list.
To define the list, it's better to create another class named "Activity" with two attributes: activeDate and driveBy (which are both strings)
public class Activity {
private String activityDate;
private String drivenBy;
...
}
Make sure to add constructors, getters and setters as well.
public class Car {
private String color;
private String year;
private List<Activity> activities;
private String maker;
...
}
There are several online tools to convert json files to Java classes, but I suggest you learn the basics and do it yourself in the future to make sure that you don't get stuck in the middle of a more complicated project.
Here is an interesting article helping you get familiar with it:
dzone.com:introduction-to-json-with-java

Related

What approach better for POJO (fields formatting logic)?

I'm working with JSON. So I have following POJO classes Position, Person.
Where Person my needed class.
I need to receive formatted values of fields only of Person (I'm using only this class, Position it's class accroding my JSON strucutre)
Where better implement formatting logic in Position or Person?
1st variant, formatting logic in Position class
public Position {
private String value;
public String getFormattedValue() {
//Value formatting...
return value;
}
public Person {
private Position position;
..other fields
public String getFormattedValue() {
return position.getFormattedValue();
}
}
//using
String neededFormattedValue = new Person().getFormattedValue();
2nd variant, formatting logic in Person class
public Position {
private String value;
public String getValue() {
return value;
}
public Person {
private Position position;
..other fields
public String getFormattedValue() {
String value = position.getValue()
//Value formatting...
return value;
}
}
//using
String neededFormattedValue = new Person().getFormattedValue();
I would suggest to have second variant, as you Position class should not have formatting logic.
The second one is more loosely coupled.
I have been having problems converting between JSON, POJO and XML.
So it seems best to use the exact name for get / set, albeit the first character - which is always capitalized.
Eg. If the fields use correct formatting, Android Studio usually suggests the methods(functions) names. Where the class contains private String value;, when you begin typing public get... AS should provide you a list. The correct syntax for the get method would be public getValue() ....
public class abc()
{
private String value;
private int some_id_of_a_record;
private String anotherString;
public String getValue()
{...}
public int getSome_id_of_a_record()
{...}
public String getAnotherString()
{...}
...
}

How to make and populate common field in recyclerview?

Let say, I have a student, employee and car class in a different structure in JSON file.
I already parse them and put the respective data to its POJO classes. The things is I wanna display data to inside a recycler view.
But here I have common field both three class is name and weight.
So, I wanna pass to list of generic to recycler view and populate them by calling like this:
tvName.setText(Object(should be generic).getName());
tvWeight.setText(Object(should be generic).getWeight());
It should display name and weight all the student, employee and car .
RecyclerView looks like
---------------------------------------------------------
CarName
CarWeight
---------------------------------------------------------
EmplyoeeName
EmplyoeeWeight
---------------------------------------------------------
StudentName
StudentWeight
---------------------------------------------------------
EmplyoeeName
EmplyoeeWeight
---------------------------------------------------------
CarName
CarWeight
---------------------------------------------------------
CarName
CarWeight
---------------------------------------------------------
StudentName
StudentWeight
Any idea would be highly appreciated.
In order to achieve that, you need something called polymorphism, learn more from StackOverflow, Java Docs and Wikipedia. In order to respect that pattern I would implement the problem like this:
I would create an Interface that has the methods you need:
public interface AttributesInterface {
String getName();
double getWeight();
}
Then I would make every POJO class implement that interface, looking in the end like this:
public class Car implements AttributesInterface {
private String name;
private double weight;
#Override
public String getName() {
return null;
}
#Override
public double getWeight() {
return weight;
}
}
In the adapter you store the list like this. If a class will implement the interface, then you will be able to add it in that array. So you will have an array that will contain Student, Car, Employee in the same time.
private List<AttributesInterface> list = new ArrayList<>();
Then final step is in onBindViewHolder where you get an object from that array and set the corresponding values.
AttributesInterface object = list.get(position);
tvName.setText(object.getName());
tvWeight.setText(String.valueOf(object.getWeight()));
Also, you mentioned that you want a solution to work with multiple classes. As long as you implement the interface in each class that needs to be displayed, you can have a million classes.
You can create only one POJO class and you can add extra variable say type. So your POJO class will look like below.
public class MyClassModel {
private String type=""; // S=Student, C=Car, E=Employee
private String name="", weight="";
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getWeight() {
return weight;
}
public void setWeight(String weight) {
this.weight = weight;
}
}
Now you will get type in your RecyclerviewAdapter so you can write your logic according to type of data.

Can I use mapped Jackson Mixin properties to create a JSON subclass when deserializing?

I have JSON output correctly annotated and mapped with mixins for the User class with appropriate setters and getters for those properties:
public class User {
String first;
String middle;
String last;
...
}
When I use my Mixin:
public interface UserMixin {
#JsonProperty("first")
void setFirst(String first);
#JsonProperty("middle")
void setMiddle(String middle);
#JsonProperty("last")
void setLast(String last);
}
After registering the mixin and writing the User class using the ObjectMapper I get:
"User" :
{
"first" : "William",
"middle" : "S",
"last" : "Preston"
}
So to this point, for brevity, I lied a little bit - User as cited above is a large, legacy DTO class that is resistant towards modification.
And, while the mixin works great, our customer would rather see something like:
"User" :
{
"Name" :
{
"first" : "William",
"middle" : "S",
"last" : "Preston"
}
...
}
I repeat, the DTO is resistant to change. Ideally I'd refactor the DTO and do it correctly.
What I think I'm asking - is there some combination of Mixin/Annotation I can use to sub-class "Name" from already existing data in the User class? There's no Name subclass ... but all of the pieces necessary to "write out" the JSON in this format exist.
Lacking the existence of a #JsonWrapped annotation, my personal preferred solution here would be to use the converter functionality of #JsonSerialize (looks like you'd need Jackson 2.3+ for this; the annotation is supported in 2.2.2 but I got unexpected runtime errors).
Basically, a converter lets you do a pre-serialization transformation from one data structure to another. This lets you work with simple data classes rather than mucking about creating a custom serializer.
First, model your DTO how you want it to be serialized:
public static class UserDto {
private final Name name;
private UserDto(Name name) { this.name = name; }
public static UserDto fromUser(User user) {
return new UserDto(Name.fromUser(user));
}
public Name getName() { return name; }
public static class Name {
private final String first;
private final String middle;
private final String last;
private Name(String first, String middle, String last) {
this.first = first;
this.middle = middle;
this.last = last;
}
public static Name fromUser(User user) {
return new Name(user.getFirst(), user.getMiddle(), user.getLast());
}
public String getFirst() { return first; }
public String getMiddle() { return middle; }
public String getLast() { return last; }
}
}
Next, create a simple Converter class (I nested it in UserDto):
public static class Converter extends StdConverter<User, UserDto> {
#Override
public UserDto convert(User value) {
return UserDto.fromUser(value);
}
}
Then, use that converter class in your mixin:
#JsonSerialize(converter = UserDto.Converter.class)
public interface UserMixin {
}

How does the Jackson mapper know what field in each Json object to assign to a class object?

Let's say I have a Json object like this:
{
"name": "Bob Dole",
"company": "Bob Dole Industries",
"phone": {
"work": "123-456-7890",
"home": "234-567-8901",
"mobile": "345-678-9012"
}
}
And to help me read it, I use Jackson's Object Mapper with the following class:
public class Contact {
public static class Phone {
private String work;
private String home;
private String mobile;
public String getWork() { return work; }
public String getHome() { return home; }
public String getMobile() { return mobile; }
public void setWork(String s) { work = s; }
public void setHome(String s) { home = s; }
public void setMobile(String s) { mobile = s; }
}
private String name;
private String company;
private Phone phone;
public String getName() { return name; }
public String getCompany() { return company; }
public Phone getPhone() { return phone; }
public void setName(String s) { name = s; }
public void setCompany(String s) { company = s; }
public void setPhone(Phone p) { phone = p; }
}
My question is, how (using the simplest explanation possible), does the Object mapper "deserialize" the Json object? I thought it was matching variable names, but changing them by a few letters didn't affect the output. Then, I tried switching the order of the set() functions, but that didn't do anything. I also tried both, but that was also useless. I'm guessing there's something more sophisticated at work here, but what?
I tried to look in the documentation and past code, but I didn't see an explanation that made sense to me.
Without Annotations:
Without any annotations, it does what is called POJO mapping, it just uses reflection on the instance members and uses some rules about how to map the keys in the json to the names of the instance members. *note: it works on private members as well as public or package protected as well
If it doesn't match the names of the instance members, then it starts trying to match the getXXX and setXXX methods, if it doesn't match anything then it gives up.
With Annotations:
It uses the metadata supplied by the annotations to do the mapping and conversions.
It is always better to explicitly use the annotations when you have the source to add them to, then there is no guess work on what gets mapped to what.
Remember explicit is always better than implicit!
This is all well documented on the WIKI:
Mapping and Annotations
JSON Schema:
I am creating JSON Schema definitions for all my new projects now to document what is and isn't valid JSON according to the schema rules engine. It is a great way to document your data structures and eliminate parsing errors.

Trying to convert JSON to Java using GSON

I am completely new to Java but have experience in other languages. I have the following JSON file that I am trying to bring into a java program.
{
"Progression": [
{
"ProgressionName": "An Apple a Day...",
"Steps": [
{
"StepName": "Collect an Apple",
"Type": "COLLECT",
"RewardType": "UNLOCK_CRAFTING",
"Reward": "minecraft:golden_apple"
},
{
"StepName": "Craft a Golden Apple",
"Type": "CRAFT",
"RewardType": "GIVE",
"Reward": "minecraft:diamond"
}
]
},
{
"ProgressionName": "Keeps the Dr Away...",
"Steps": [
{
"StepName": "Collect an Apple",
"Type": "COLLECT",
"RewardType": "UNLOCK_CRAFTING",
"Reward": "minecraft:golden_apple"
},
{
"StepName": "Craft a Golden Apple",
"Type": "CRAFT",
"RewardType": "GIVE",
"Reward": "minecraft:diamond"
}
]
}
]
}
I have the following class that I thought was correct to store the JSON:
public class ProgressionData {
private Progression progresion;
public class Progression {
private String ProgressionName;
private ProgressionSteps Steps;
}
public class ProgressionSteps {
private String StepName;
private String Type;
private String RewardType;
private String Reward;
}
}
This is the call I am using:
BufferedReader br = new BufferedReader(new FileReader(configFile));
ProgressionData progressiondata = new Gson().fromJson(br, ProgressionData.class);
When I debug the code, progressiondata is NULL. I know I am missing something fundamental, and hoping someone can point me in the right direction.
you are trying to map an array of Progression objects to a Progression object,
change from
private Progression progresion;
to
private List<Progression> progresion;
or
private Progression[] progresion;
and the same thing for Progression Step objects
also, don't forget create getters/setters for your members or change access modifiers
Your class is wrong since you have JSONArray inside, please try the following:
public class ProgressionData {
private List<Progression> progresion;
public class Progression {
private String ProgressionName;
private List<ProgressionSteps> Steps;
}
public class ProgressionSteps {
private String StepName;
private String Type;
private String RewardType;
private String Reward;
}
}
Given your example, your base class should look something like the above:
public class ProgressionData {
private Progression[] progresion;
public class Progression {
private String ProgressionName;
private ProgressionSteps[] Steps;
// Add getters and setters
}
public class ProgressionSteps {
private String StepName;
private String Type;
private String RewardType;
private String Reward;
// Add getters and setters
}
// Add getter and setter for "Progression"
}
Notes:
progression and steps fields are actually arrays.
You need to add getters and setters methods for your properties.
You may experience some issues because you are parsing a Property (starting with upper-case P) key from your json to a property (lower-case p). If you try to change your field to Property, the compiler will probably complain because you can't have either a Class and a Field with the same name. In that case, you must look for some GSON parsing options (for ignoring case, for example).
You should update following things to make it work
There is a typo in progresion, it should be Progression. (This might be the primary reason for getting your object as Null, and Name of the variables should match with keys in Json, not classname. You can also use annotation in your POGO class to map the name of the variable with key using #SerializedName("Progression"))
Progression is an array
Steps inside Progression is an array
Please update your ProgressionData as below.
public class ProgressionData {
#SerializedName("Progression")
private List<Progression> progression;
public class Progression {
private String ProgressionName;
private List<ProgressionSteps> Steps;
//Setters and Getters
}
public class ProgressionSteps {
private String StepName;
private String Type;
private String RewardType;
private String Reward;
//Setters and Getters
}
//Setters and Getters
}
Use below code to parse your json,
BufferedReader br = new BufferedReader(new FileReader(configFile));
ProgressionData progressiondata = new Gson().fromJson(br, ProgressionData.class);

Categories