How do I transform a dynamic json to java class? - java

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>();
}

Related

How to deserialize a list to a map using fastmap

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?

JACKSON with JSON: map unrecognized fields [duplicate]

This question already has answers here:
Collecting unknown properties with Jackson
(2 answers)
Closed 6 years ago.
I need to convert a JSON string into a Java object. The JSON will have a few known fields and some unknown ones. Here is an example:
public class MyJsonBean {
private String abc;
private String def;
// getters and setters
}
And the JSON I want to parse:
{"abc":"value1","def":"value2","ghi":"value3","jkl":"value4"}
Only fixed fields are "abc" and "def". Other fields are variable.
I'd like Jackson to parse the variable fields and put them into a list/map within the MyJsonBean class. Is there any way to do that?
Use the #JsonAnySetter Called by json deserialization to store non-member elements of the json object. Stores the value in the otherAnnotations field.
Jackson can actually be made to work with such POJOs: here is one way to do it:
public class MyJsonBean
{
// Two mandatory properties
protected final String abc;
protected final String def;
// and then "other" stuff:
protected Map<String,Object> other = new HashMap<String,Object>();
// Could alternatively add setters, but since these are mandatory
#JsonCreator
public MyJsonBean (#JsonProperty("abc") String abc, #JsonProperty("def") String def)
{
this.abc = abc;
this.def = def;
}
public int getId() { return id; }
public String getName() { return name; }
public Object get(String name) {
return other.get(name);
}
// "any getter" needed for serialization
#JsonAnyGetter
public Map<String,Object> any() {
return other;
}
#JsonAnySetter
public void set(String name, Object value) {
other.put(name, value);
}
}
And there we have it: serializes and deserializes nicely.
Share and enjoy... :)

Java Enum to String Map maintaining consistency

I am new to Java and working on writing a Enum to String Map for headers.
public class Header {
// When adding HeaderType make sure it is consistent with the header name map
public enum HeaderType {
MARKER,
WIDTH,
......
};
private String name;
private String value;
private HeaderType headerType;
// Create an immutable map for header enum to header names
private static final Map<HeaderType, String> headerNameMap;
static {
Map<HeaderType, String> headerNameMapTemp = new HashMap<HeaderType, String>();
headerNameMapTemp.put(HeaderType.MARKER, "MA");
headerNameMapTemp.put(HeaderType.WIDTH, "WI");
headerNameMap = Collections.unmodifiableMap(headerNameMapTemp);
}
public Header(HeaderType headerType, String value) {
this.headerType = headerType;
this.name = Header.getHeaderName(this.headerType);
this.value = value;
}
private static String getHeaderName(HeaderType headerType) {
return headerName.get(headerType);
}
In the above code I use HeaderType enum and use an immutable HashMap to convert from enum to header name. As you can see adding another header type involves adding it in the map as well. So the user of this should make sure it's added in two places to avoid any mess later. Are their any clean alternatives for this functionality?
You can make the header name a field in the enum itself, like this:
public enum HeaderType {
MARKER("MA"),
WIDTH("WI");
// FOO(), BAR; Won't compile
private final String name;
private HeaderType(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
This way it will not be possible to add a new HeaderType without specifying a corresponding name as well and your getHeaderName method could simply be replaced with a call to getName().
You can enumerate all type/name combinations using the enum's values() method:
for (HeaderType headerType : HeaderType.values()) {
System.out.println(headerType.getName());
}
Running sample: https://ideone.com/B5LwQz

Serialize/deserialize immutable objects that carry extra informations with Jackson

I try to use only immutables objects in my application. I've got a REST service that will take arbitrary JSon objects as input.
I've a Java class that map theses objects, and I want to make them immutable + able to deal with extra parameters (just like using #JsonAnySetter).
Here is my java class:
public class Operation {
private final String _id;
private final String state;
private final Map<String, Object> extra;
public Operation(String _id, String state, Map<String,Object> extra) {
this._id = _id;
this.state = state;
this.extra = extra;
}
// getters....
}
Using #JsonAnySetter I would have:
public class Operation {
private final String _id;
private final String state;
private Map<String, Object> extra = new HashMap<>();
public Operation(String _id, String state) {
this._id = _id;
this.state = state;
}
#JsonAnySetter
public void addExtra(String key, Object value) {
this.extra.put(key,value);
}
// getters....
}
But this is not immutable anymore !
This will not work because Jackson do not find any "extra" json attribute to read. I would like that everything that cannot be mapped be added to my map.
Any idea of how to do this ? (or is it just possible :)
Note: I use javac with -parameters option and the ParameterNameModule from jackson so that I don't need #JsonCreator option.
Ok so I respond to myself :)
It seems that it is not possible to do that using only Jackson.
Because I want immutability, I've turned myself to the 'immutables' framework: http://immutables.github.io/
With a little configuration, it will deal with extra parameters as stated in the following report: https://github.com/immutables/immutables/issues/185.
In my situation, I've got the following code:
#Value.Immutable
#JsonSerialize(as = ImmutableOperation.class)
#JsonDeserialize(as = ImmutableOperation.class)
public abstract class Operation {
#JsonAnyGetter
#Value.Parameter
public abstract Map<String, String> extra();
}
Refer to the documentation of immutables for the details.
If you want to deserialize immutable entity with extra arguments you can utilize builder pattern:
#JsonPOJOBuilder
public class OperationBuilder {
private String _id;
private String _state;
private Map<String, Object> extra = new HashMap<>();
#JsonAnySetter
public OperationBuilder addExtra(String key, Object value) {
this.extra.put(key,value);
return this;
}
// setters....
public Operation build() {
return new Operation(...arguments...)
}
And your original class should have this annotation on a class level:
#JsonDeserializer(builder = OperationBuilder.class)
This way all your known and unknown (extra) fields will be populated inside the builder and then Jackson will call build() method at the end of the deserialization.

Jackson Databind - get properties not specified in pojo

I'm trying to figure out how can I bind json to POJO.
When json can sometime contain additional fields depending on various conditions. Basically speaking - some part of json will always contain same properties,
for example: name and age. But sometimes I'll get shoeSize and/or eyeColor. I cant make list of all possible properties that can be passed to me, because some of them are defined by user.
Is there possibility to achieve something like this?
class MyClass
{
public String name;
public Integer age;
public Map<String, String> additionalArguments;
public MyClass(...) {...}
}
After going through documentation (again) I found annotation called JsonAnySetter and process reverting annotation JsonAnyGetter
class MyClass
{
public String name;
public Integer age;
public Map<String, String> additionalArguments = new HashMap<>();
public MyClass(...) {...}
#JsonAnyGetter
public Map<String,Object> getAdditionalProperties() {
return additionalProperties;
}
#JsonAnySetter
public void putAdditionalProperty(String name, Object value) {
additionalProperties.put(name, value);
}
}

Categories