I have a JSON that has a list of objects inside another object, something like:
{
"name":"name",
"processes":[
{
"id":123,
"desc":"main"
},
{
"id":456,
"desc":"secondary"
}
]
}
I want to parse fastjson to something like:
public class Idea {
private String name;
private Map<String, List<Process>> processes;
//Getters and setters
}
and
public class Process {
private String id;
private String desc;
//Getters and setters
}
Basically, the idea is to map that list from the JSON to a map where the key is something like Processes and the values are the list got from the JSON.
Any idea on how I could do it?
Related
I have a json request coming from a service. The service consist of few data entries.
{
dataPair {
keyA : valueA
keyB : valueB
....
}
name: string
addr: string
}
}
Originally I have below pojo classes
Class ServiceRequest {
public String name;
public String addr;
public DataPair dataPair;
}
Class dataPair {
public String keyA;
public String keyB;
//...
}
But now I wanted to have dataPair to be dynamic so whatever key-value pair we receive we will able to get it without changing the class.
I was wondering how should I change dataPair class or is there a way to generate key-value pair fields?
Could you use Retrofit 2.0? https://square.github.io/retrofit/
It easy works with converting dynamic json to Java collections like List or Map.
And so pojo class will be:
Class ServiceRequest {
public String name;
public String addr;
public HashMap<String, String> dataPair;
}
What about this approach:
Class dataPair {
private HashMap<String, String> dt= new HashMap<String, String>();
}
I have to generate strange json from object(with jackson ObjectMapper), something like:
{
"data":{
"id":"1",
"name":"Json"
},
"userType":"MD"
}
But, with jackson data-bind i can do only:
{
"id":"1",
"name":"Json",
"userType":"MD"
}
With User.class:
public class User {
private String id;
private String name;
private String userType;
//Getters Setters Constructor
I found two ways of bypassing. First one - to use another "superclass":
public class Data {
#JsonProperty("data")
private User user;
private String userType;
//Getters Setters Constructor
Second way - to use Map:
Map<String, Object> map = new HashMap<>();
map.put("data", user);
map.put("userType", "MD");
String json = objMapper.writeValueAsString(map);
But i think, that it's not idea to use this ways if i have about 8 different objects with such structure. So, what's best pratice? Or maybe there are another built in ways?
I want to find the best one
The first approach you mentioned is the best practice, but it is called Composition (HAS-A relationship) rather 'superclass' and just to add readability, you can refactor your classes like this:
public class User {
private Data data;
private String userType;
//Getters Setters Constructor
}
public class Data {
private String id;
private String name;
// getters and setters
}
So, when you marshal your pojo to json, structure will be:
{
"data":{
"id":"1",
"name":"Json"
},
"userType":"MD"
}
which is what you want! Happy coding :)
Update: If you are generating your API documentation with Swagger or Open API Spec, then there is no way to have a representation of your model if you use Map or HashMap. So, obviously, the first approach is the one you should consider!
I have a model like this:
public class Employee {
#JsonProperty("emplyee_id")
private Integer id;
#JsonProperty("emplyee_first_name")
private String firstName;
#JsonProperty("emplyee_last_name")
private String lastName;
#JsonProperty("emplyee_address")
private String address;
#JsonProperty("emplyee_age")
private Byte age;
#JsonProperty("emplyee_level")
private Byte level;
//getters and setters
}
now I need to create two JSONs using this (only) model.
the first one must like this for example:
{
"employee_id":101,
"employee_first_name":"Alex",
"employee_last_name":"Light",
"employee_age":null,
"employee_address":null
}
and the second one must like this for example:
{
"employee_id":101,
"employee_level":5
}
by the way, I already tested #JsonIgnore and #JsonInclude(JsonInclude.Include.NON_NULL).
the problem of the first one (as much as I know) is, those fields can't be included in other JSONs (for example if level get this annotation, it won't be included in the second JSON)
and the problem of the second one is, null values can't be included in JSON.
so can I keep null values and prevent some other property to be included in JSON without creating extra models? if the answer is yes, so how can I do it? if it's not I really appreciate if anyone gives me the best solution for this state.
thanks very much.
it could be useful for you using #JsonView annotation
public class Views {
public static class Public {
}
public static class Base {
}
}
public class Employee {
#JsonProperty("emplyee_id")
#JsonView({View.Public.class,View.Base.class})
private Integer id;
#JsonProperty("emplyee_first_name")
#JsonView(View.Public.class)
private String firstName;
#JsonProperty("emplyee_last_name")
#JsonView(View.Public.class)
private String lastName;
#JsonProperty("emplyee_address")
private String address;
#JsonProperty("emplyee_age")
private Byte age;
#JsonProperty("emplyee_level")
#JsonView(View.Base.class)
private Byte level;
//getters and setters
}
in your json response add #JsonView(Public/Base.class) it will return based on jsonview annotations
//requestmapping
#JsonView(View.Public.class)
public ResponseEntity<Employee> getEmployeeWithPublicView(){
//do something
}
response:
{
"employee_id":101,
"employee_first_name":"Alex",
"employee_last_name":"Light",
"employee_age":null,
"employee_address":null
}
for the second one
//requestmapping
#JsonView(View.Base.class)
public ResponseEntity<Employee> getEmployeeWithBaseView(){
//do something
}
response
{
"employee_id":101,
"employee_level":5
}
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 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: "..." },
...
]
}