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);
Related
{
"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
I have a class like:
class Car {
private Engine myEngine;
#JsonProperty("color")
private String myColor;
#JsonProperty("maxspeed")
private int myMaxspeed;
#JsonGetter("color")
public String getColor()
{
return myColor;
}
#JsonGetter("maxspeed")
public String getMaxspeed()
{
return myMaxspeed;
}
public Engine getEngine()
{
return myEngine;
}
}
and Engine class like
class Engine {
#JsonProperty("fueltype")
private String myFueltype;
#JsonProperty("enginetype")
private String myEnginetype;
#JsonGetter("fueltype")
public String getFueltype()
{
return myFueltype;
}
#JsonGetter("enginetype")
public String getEnginetype()
{
return myEnginetype;
}
}
I want to convert the Car object to JSON using Jackson with structure like
'car': {
'color': 'red',
'maxspeed': '200',
'fueltype': 'diesel',
'enginetype': 'four-stroke'
}
I have tried answer provided in this but it doesn't work for me as field names are different then getter
I know I can use #JsonUnwrapped on engine if field name was engine. But how to do in this situation.
provide #JsonUnwrapped and #JsonProperty together:
#JsonUnwrapped
#JsonProperty("engine")
private Engine myEngine;
You shall use the #JsonUnwrapped as follows in the Car class for the desired JSON object:
class Car {
#JsonUnwrapped
private Engine myEngine;
#JsonProperty("color")
private String myColor;
#JsonProperty("maxspeed")
private int myMaxspeed;
...
I think the best solution here would be to use #JsonValue annotation over the myEngineType attribute in your Engine class, it will only serialize this attribute instead of the whole Engine object.
So your code would be like this:
class Engine {
#JsonProperty("fueltype")
private String myFueltype;
#JsonValue
#JsonProperty("enginetype")
private String myEnginetype;
}
You can take a look at this answer for more details.
I've been trying to improve my code on this but don't know how, the json i get is this:
{
"name": "Jhon",
"lastName": "Smith",
"clothes": {
"gender":"male",
"Shirt": {
"id": 113608,
"name": "Green Shirt",
"size": "Large"
},
"Pants": {
"id": 115801,
"name": "Black Leather Pants",
"size": "Large"
}
}
}
The way it works so far is having both Shirt and Pants classes but as they are identical im trying to use just one class that will get both of them.I have no say in how the json is generated so have to work with it as it comes.
This are my classes:
Class Person
public class Person{
private String lastName;
private String name;
private Clothes clothes;
}
Class Clothes
public class Clothes{
private Shirt Shirt;
private Pants pants;
private String gender;
}
Class Shirt
public class Shirt{
private String id;
private String name;
private String size;
}
Pants is the same as shirt, the thing is that i don't want my code to break if/when they decide to add another piece of clothing so i'm trying to do something like this
Class Clothes
public class Clothes{
private List<Something> clothList;
private String gender;
}
Instead of using 2 separate classes (Shirt and Pants) simply use one class - let's say Cloth. Tried it like that and worked fine:
Person class:
package com.dominikangerer.q29550820;
public class Person {
private String name;
private String lastName;
private Clothes clothes;
}
Clothes class:
package com.dominikangerer.q29550820;
public class Clothes {
private String gender;
private Cloth Shirt;
private Cloth Pants;
}
Cloth class:
package com.dominikangerer.q29550820;
public class Cloth {
private Integer id;
private String name;
private String size;
}
After Building these classes I tried it directly in a little main class which results in a perfectly fine deserialized.
Gson g = new Gson();
Person person = g.fromJson("{\"name\":\"Jhon\",\"lastName\":\"Smith\",\"clothes\":{\"gender\":\"male\",\"Shirt\":{\"id\":113608,\"name\":\"Green Shirt\",\"size\":\"Large\"},\"Pants\":{\"id\":115801,\"name\":\"Black Leather Pants\",\"size\":\"Large\"}}}", Person.class);
Didn't use #Expose here or #SerializedName("something") because it wasn't needed.
Hope it helps you out - otherwise please explain your problem in more detail and I will try to help you.
----------- Update ------------
Okay normally it's quite easy to cast a Json as you have it there in an normal Object - but the thing is inside the map (clothes) you have also a normal String value. For this purpose I would suggest you to enable the Gson functionality #Expose I will tell you why this would be a good idea later.
Let's start:
I removed the Clothes class with a Map<String, Object> which Gson can easily deserialize - problem here was that the we also have the gender inside that map. I modified the Person class which now works like this:
Person v2:
package com.dominikangerer.q29550820;
public class Person {
private String name;
private String lastName;
#SerializedName("clothes")
private Map<String, Object> clothesWrapper;
public String getGender() {
return clothesWrapper.get("gender").toString();
}
public void setGender(String gender) {
this.clothesWrapper.put("gender", gender);
}
}
Now we can already map the gender as String and modify it with the getter and setter - still have the map up there which contains Objects. Next thing we don't want the Map<String, Object> - for deserializing and serialization it's totally fine - but for working with the Cloths itself - it's stupid so let's get rid of it with the easiest way:
We modify our Person class like this:
Person v3:
package com.dominikangerer.q29550820;
public class Person {
#Expose
private String name;
#Expose
private String lastName;
#Expose
#SerializedName("clothes")
private Map<String, Object> clothesWrapper;
private Map<String, Cloth> clothes;
public String getGender() {
return clothesWrapper.get("gender").toString();
}
public void setGender(String gender) {
this.clothesWrapper.put("gender", gender);
}
public Map<String, Cloth> getClothes() {
if (clothes == null) {
Gson g = new Gson();
clothes = new HashMap<String, Cloth>();
for (Entry<String, Object> entry : clothesWrapper.entrySet()) {
if (entry.getKey().equals("gender")) {
continue;
}
String helper = g.toJson(entry.getValue());
Cloth cloth = g.fromJson(helper, Cloth.class);
clothes.put(entry.getKey(), cloth);
}
}
return clothes;
}
}
As you can see we now indirectly cast all the Clothes - we have to do this like that because it's the easiest way to get all the LinkedTreeMap to a Cloth-Object without running into a ClassCastException. As you can see we now have a Map<String,Object> clothesWrapper which let Gson Parse the object (can't find a better name - sorry) and the Map<String, Cloth> clothes map without Expose. Now you also need to setup the Gson with the enableExpose option which works like this:
(Using the Person v3 Class here - simply debug into it - works like a charm)
public class Main {
public static void main(String[] args) {
Gson g = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
Person person = g.fromJson("{\"name\":\"Jhon\",\"lastName\":\"Smith\",\"clothes\":{\"gender\":\"male\",\"Shirt\":{\"id\":113608,\"name\":\"Green Shirt\",\"size\":\"Large\"},\"Pants\":{\"id\":115801,\"name\":\"Black Leather Pants\",\"size\":\"Large\"}}}", Person.class);
System.out.println(person.getClothes());
System.out.println(person.getGender());
}
}
You can find all classes in this github repository
I'm trying to convert an existing class to use generics, and am getting stumped while converting the constructors.
The original class was a POJO that contained logic for moving from one room to another in a text-based console game. Literally, it was a class that held some string triggers that would fire the action (eg. the user types "walk right"), a description, and a pointer to the new Location.
The current, non generic version of the class looks like this:
public class Navigation implements Serializable {
private static final long serialVersionUID = 1L;
private String trigger;
private String description;
private Location target;
public Navigation() {
this("", "", new Location());
}
public Navigation(String trigger, String description, Location target) {
this.trigger = trigger;
this.description = description;
this.target = target;
}
// plus getters, setters, etc.
}
(The Location class is another POJO that describes a location. It is irrelevant.)
I want to extend the Navigation class to be able to handle targets that are not Locations. I thought that the best way to do this would be to convert the Navigation class to use generics, so I tried this:
public class Navigation<T> implements Serializable {
private static final long serialVersionUID = 2L;
private String trigger;
private String description;
private T target;
public Navigation() {
this("", "", new T());
}
public Navigation(String trigger, String description, T target) {
this.trigger = trigger;
this.description = description;
this.target = target;
}
// plus getters, setters, etc.
}
However, this doesn't compile at the line this("", "", new T()); because T cannot be instantiated. Is is possible to instantiate the generic type object in this context?
You basically have two choices:
1.Require an instance:
public Navigation(T t) {
this("", "", t);
}
2.Require a class instance:
public Navigation(Class<T> c) {
this("", "", c.newInstance());
}
You could use a factory pattern, but ultimately you'll face this same issue, but just push it elsewhere in the code.
No, and the fact that you want to seems like a bad idea. Do you really need a default constructor like this?
You cannot do new T() due to type erasure. The default constructor can only be
public Navigation() {
this("", "", null);
}
You can create other constructors to provide default values for trigger and description. You need an concrete object of T.
I will be recieving JSON strings in the following format:
{ "type":"groups", "groups":[ {"group":"NAME"}, ...] }
How would one form an object so that the following would work.
MyClass p = gson.fromJson(jsonString, MyClass.class);
The part I'm stuck it is "{"group":"NAME"}". Would this be fixed by saving objects inside the an array? Example.
public class MyClass {
private String type;
private List<MyOtherClass> groups = new ArrayList<MyOtherClass>();
//getter and setter methods
}
Answer: Nesting objects in each other doh! Thanks you guys! Crystal clear now :D
public class MyOtherClass {
private String group;
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
#Override
public String toString() {
return "group: "+group;
}
}
First you need a POJO for the group:
public class MyOtherClass {
#Expose
private String group;
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
}
Next you need one for your 'MyClass', which would look like this:
public class MyClass {
#Expose
private String type;
#Expose
private List<MyOtherClass> groups = new ArrayList<MyOtherClass>();
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<Group> getGroups() {
return groups;
}
public void setGroups(List<Group> groups) {
this.groups = groups;
}
}
Hope this helps.
At first glance, this looks fine, assuming MyOtherClass has a field called group that holds a String. What do you mean by "the part I'm stuck [on]"? Perhaps you could post the stack trace you're seeing, a broader description of what you're trying to do, or best of all a SSCCE?
When using GSON, I find it easiest to implement the class structure I need, then let GSON generate the JSON data from that. You certainly can go the other way (design class structure based on JSON data), but I think it's more confusing if you don't understand what GSON is trying to do.
Some pseduo-code:
Class MyClass
String type
List<MyOtherClass> groups
Class MyOtherClass
String group
Looking at this we can easily see the JSON that will hold our serialized object will look like so:
{
type: "...",
groups: [
{ group: "..." },
...
]
}