Remove null values from json using jackson - java

I am trying to remove all the null values from my json.
{
"key" : null
}
I have used:
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(Include.NON_NULL);
Here "key" is a list and so when I use the above serialization option, the json gets converted to:
{
"key" : []
}
I want the json to be:
{
}
I don't want to use
Include.NON_EMPTY
as I have other json in my project where I need to show the empty list and 0 valued keys. Is there any way to remove the null valued keys when it is a list, the same way it does for a string value?
I cannot use annotations as the class files are being generated from xml using jaxb. Class Structure:
public class C1 {
protected List<C2> key;
public List<C2> getKey() {
if (key == null) {
key = new ArrayList<C2>();
}
return this.key;
}
}
I have been stuck for a while now. Any help is highly appreciated. Thanks in advance.

To suppress serializing properties with null values,
you can configure the ObjectMapper directly using this.
mapper.setSerializationInclusion(Include.NON_NULL);

Related

Converting JSON Array to Java Array always throws empty values

So I have this variable specCifDetailsReturn which contains the ff. payload
[
{"ax21:cHType":"S",
"ax21:cardNumber":4***********7126,"ax21:returnCde":"00",
"ax21:cancelCode":"",
"ax21:vipCode":"",
"ax21:custrNbr":"0*****3426"},
{"ax21:cHType":"S",
"ax21:cardNumber":4***********3038,"ax21:returnCde":"00",
"ax21:cancelCode":"H",
"ax21:vipCode":"",
"ax21:custrNbr":"0*****3426"}
]
And the ff. Model Class to extract the params I need from the Array
#Data
#AllArgsConstructor
#NoArgsConstructor
#JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
public final class SpecCifInfo {
#JsonAlias("ax21:cHType")
private String cHType;
#JsonAlias("ax21:cardNumber")
private String cardNumber;
}
I am trying to convert it to a Java ArrayList so that I could loop into it and find a card number. But for some reason it always throws a null value on the log even though the specCifDetailsReturn variable has a value. Below is the snippet of my code.
Gson gson = new Gson();
Type type = new TypeToken<List<SpecCifInfo>>(){}.getType();
ArrayList<SpecCifInfo> specDetails = gson.fromJson(specCifDetailsReturn.toString(),type);
for (SpecCifInfo specInfo : specDetails){
LOGGER.debug("Spec CIF Details", specInfo.getCHType() + "-" + specInfo.getCardNumber());
}
Sample Output of the SpecCifInfo Object that has null values
Those annotations are for the Jackson library, and you are manually using Gson. You should either keep them and just let Spring handle the deserialization for you by specifying a List<SpecCifInfo> parameter in the controller method, or you should use GSON's #SerializedName annotation. Either way will work.

Create an universal java mapper for json string

I'm working on a Spring-boot project where I receive different format of Json String. My goal is to convert these Json string into an Unified Java class.
I can receive many variations of this Json:
{ "id" : "someId", "type" : "temperature", "value" : 21.0 }
For example, one variation might look like :
{ "id" : "someId", "data" : { "type": "temp", "val" : 21.0 }, "location": "here" }
So these 2 Json must be mapped into the same Java class.
I already have 2 solutions in mind :
First solution
1) Create a Specific Java Class for each Json that I may receive
2) Create a function that takes this specific object and return the Unified Java Class
Second solution
1) Create a JsonNode with the Json String
2) For each key try to match it with a field of the Unified Java Class.
But we have to take into consideration every key possible of a node like "value" or "val".
What is the best approach to solve this problem ?
I'm looking for a solution that could be easy to maintain.
Edit : I'm already using Jackson, but my problem is to map this Json object into an universal Java Class independently of the Json
Edit 2 : The Unified Java Class is a class model that already exist and it's used to store information in our database. So to push information inside our database, I have to convert each json I receive into this unified format
I can see following solutions. E.g. you use Jackson for parse JSON you could declare you custom ObjectMapper:
ObjectMapper mapper = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
This mapper contains additional options to ignore unknow properties.
Do you Map<String, Object> as destination class. This is magic key and it works always. Contra: you do not have json validation and have to add many constant keys to read this.
Example:
public static <T> Map<String, T> readMap(String json) throws NGPException {
if (json == null) {
return null;
}
ObjectReader reader = JSON_MAPPER.readerFor(Map.class);
MappingIterator<Map<String, T>> it = reader.readValues(json);
if (it.hasNextValue()) {
Map<String, T> res = it.next();
return res.isEmpty() ? Collections.emptyMap() : res;
}
return Collections.emptyMap();
}
Client:
Map<String, Object> map = readMap("json string");
String id = (String)map.getOrDefault("id", null);
Second way is to build one general class that contain all posiible variables. Additionnaly you have to set option to Jackson ignore unknown fields. In this case, existed fields will be used by Jackson.
Example:
public static <T> T read(String json, Class<T> clazz) throws NGPException {
return mapper.readerFor(clazz).readValue(json);
}
class Response {
private String id;
private String type;
private Double value;
private String location;
private Data data;
public class Data {
private String type;
private String temp;
private Double value;
}
}
Client:
Response response = read("json string", Response.class);
I usually use GSon from Google. It is really usefull. Check gson.fromJson(yourJsonString) in your case.
You can easy use
Gson gson = new Gson();
Data data = gson.fromJson(jsonString, Data.class);

Jackson: can json specify the target type?

This is what my class looks like -
public class A {
private Map<String, Object> objects = null;
....
}
My json would be like -
{
"f1" : {
"name" : "some name",
"val" : 3
},
"f2" : {
"arg": {
some field/value pairs
}
}
}
What I want is to specify in the JSON itself the type to which it can be deserialized to. So the value for f1 would be converted to an object of class B and f2 would get converted to object of C.
My code will look like this -
Object o = objects.get("f1");
if (o instanceof B) {
...
} else if (o instanceof C) {
...
}
Is there a way to do this? I want the json to control the deserialization.
Yes, Jackson can use a type identifier if JSON document has it. This is usually done by using annotation #JsonTypeInfo.
There are multiple ways to add/use type identifier, both regarding how it is included in JSON document, and as to what kind of id is being used (type name or Java class name?).
The easiest way to see how things match is to actually start with a POJO, add #JsonTypeInfo annotation, and serialize it to see kind of JSON produced. And once you understood how inclusion works you can modify, if necessary, structure of JSON and/or Java class definition.

Marshaling list of objects containing maps of objects to JSON

I have this object structure which I'm trying to annotate with Jackson to marshal/unmarshal to a JSON file.
public class A {
List<B> bList;
}
public class B {
String attr;
Map<String, C> map;
}
public class C {
#JsonIgnore
String name;
String value;
}
A has a list of B's and B has a map of C's where the key of the map is the name attribute of C. I want the JSON to look like this if possible:
{
"bList" : [
{
"attr":"itsValue"
"KEY_IN_MAP":"VALUE_IN_C",
"KEY_2_IN_MAP":"VALUE_2_IN_C"
}
]
}
Where KEY_IN_MAP is the name of C as the key in B's map and VALUE_IN_C is the value of the value object in the map. I've tried annotating a put method for the map:
#JsonAnySetter
private void put(String name, C value) {
map.put(name, c);
}
But marshaling this gives me:
{
"bList" : [
{
"attr":"itsValue"
"KEY_IN_MAP": {
"value":"VALUE_IN_C",
},
"KEY_2_IN_MAP": {
"value":"VALUE_2_IN_C"
}
}
]
}
Is there any way to get the above mapping with Jackson or any other JSON serializing library? My goal is to get rid of the redundancy of writing "value" every time and compress the file as much as possible.
The map in B could be turned into a list of C but I still need the mapping to be
{"name" : "value"} for each object C
Here are few suggestions that I have:
Make your Map<String,C> to be a Map<String,String>.
You can also make your Map<String,C> to be List<C>.
Please have a look at the other thread which discusses the same.

Jackson ObjectMapper with arbitrary JSON keys

I'm using Jackson 1.9.5 in an Android project to parse JSON files.
So far I haven't had any problems, and can parse files fine using the following code:
AssetManager mgr = getAssets();
ObjectMapper mapper = new ObjectMapper();
try {
InputStream ifp = mgr.open("detail_schema.json");
schema = mapper.readValue(ifp, DetailSchema.class);
} catch (IOException e) {
e.printStackTrace();
}
Where the DetailSchema class consists of a mix of primitive types and classes. I'm now running into a problem where I want to parse some JSON like the following:
"fields": {
"Suburb": "Paddington",
"State": "NSW",
"Post Code": "2074",
"Lollipop": "Foo Bar Haz"
}
Where I can't possibly know the map keys before hand (they can be user-defined). As such, I'm not sure what the associated Java class should look like.
Ie, for this example, it could look like:
public class MyClass {
public String Suburb;
public String State;
public String PostCode;
public String Lollipop;
}
But this may not be correct for another instance of the JSON file. Ideally I need some way for Jackson to map values to something like a NameValuePair. I suspect that the automatic object mapping may not be an option in this case - can someone confirm or deny this?
You have two options. Either you can use readTree in ObjectMapper, which returns a JsonNode. Working with a JsonNode is much like working with a tree, so you can get children nodes, read values, et cetera:
InputStream ifp = mgr.open("detail_schema.json");
JsonNode root = mapper.readTree(ifp);
JsonNode fields = root.get("fields");
for (JsonNode children : fields) {
// ...
}
Then you'd need to build your DetailSchema object manually.
Or, you can let Jackson deserialize it as a Map, in which case you'd use your code but where MyClass would be like this:
public class MyClass {
public Map<String, Object> fields;
// getter/setters
}
You can probably type the map values as String as well if you are sure the inputs are text in json. (Actually, I'm not sure what type enforcement Jackson does, maybe it will allow anything anyway...)

Categories

Resources