Serialize JSON file with GSON in java - java

I want to convert this JSON into objects in java:
{
"mapping": [
{
"boardPosition": {
"row": 1,
"col": 1
},
"nodeId": 3242324
},
{
"boardPosition": {
"row": 1,
"col": 2
},
"nodeId": 432423
},
{
"boardPosition": {
"row": 1,
"col": 3
},
"nodeId": 424324132
}
]
}
this is how I created my java classes
class MapeoWumpus {
public mapp mapping;
}
class mapp{
public boardP boardPosition;
public String nodeId;
}
class boardP{
public int row;
public int col;
}
and then when I try to convert my file like this
MapeoWumpus mapa=new MapeoWumpus();
mapa=gson.fromJson(filetext, MapeoWumpus.class);
I get a null object
What can I do?
EDIT: This is my entire code:
package parserjson;
import java.io.FileNotFoundException;
import java.util.*;
import com.google.gson.*;
public class Main {
/**
* #param args
*/
public static void main(String[] args) throws FileNotFoundException {
String filetext;
ParserJson parser=new ParserJson();
Gson gson=new Gson();
MapeoWumpus mapa=new MapeoWumpus();
filetext=parser.leerArchivo("b1.json");
mapa=gson.fromJson(filetext, MapeoWumpus.class);
}
}
"leerArchivo" is just a method to get the json file, as you can see my json file is in a string variable

You should define instance variable mapp as array. Because your JSON data seems to contain mapping array.
class MapeoWumpus {
public mapp[] mapping;
}
Creating new MapeoWumpus in the below code is unnecessary
MapeoWumpus mapa=new MapeoWumpus();
mapa=gson.fromJson(filetext, MapeoWumpus.class);
Just change it as follows
MapeoWumpus mapa=gson.fromJson(filetext, MapeoWumpus.class);

Related

Parse a nested dynamic module using Gson

I have a JSON that looks more or less like this:
{
"modules": {
"someExistingModule": {
"name": "pug",
...
},
"randomExistingModule": {
"type": "cat",
...
},
"myNewModule": { // <----- I care about this module. Note that this is NOT an array
"modules": {
"img1": {
"type": "image",
"url": "https://some/random/image,
"altText": "Some image description
},
"img2": {
"type": "image",
"url": "https://some/random/image,
"altText": "Some image description
},
"img3": {
"type": "image",
"url": "https://some/random/image,
"altText": "Some image description
},
"txt1": { // <------ Updated JSON
"type": "text",
"content": "Hello world 1"
},
"txt2": {
"type": "text",
"content": "Hello world 2"
},
...
}
}
Inside myModule there can be N number of imgN objects and txtN. I need to parse this dynamically.
My current Response class looks like this:
public class MyModuleResponse extends SomeResponseClass
{
#Override
public void parse(InputStream data)
{
T responseBody = readJsonStream(data, MyModuleResponseBody.class());
MyModuleDataParser.parse(responseBody);
}
MyModuleDataParser.java
...
public static MyModuleDataParser parse(#Nullable MyModuleResponseBody body)
{
parseSomeExistingModule();
parseRandomExistingModule();
parseMyNewModule(); // <--- This is the new module I'm trying to parse. Currently, this method is empty.
}
MyModuleResponseBody.java
public class MyModuleResponseBody
{
public Modules modules;
public static class Modules
{
SomeExistingModule someExistingModule;
RandomExistingModule randomExistingModule;
MyNewModule myNewModule; // <----- My new module
}
public static class SomeExistingModule
{
String name;
...
}
public static class RandomExistingModule
{
String type;
...
}
public static class MyNewModule
{
public ??? modules; // <--- Trying to define the Type here. Something like List<MyImageModule>. But, it won't work
}
MyImageModule.java
public class MyImageModule extends Module // <---- Update: This class now extends a generic Module class
{
private String url;
private String altText;
}
MyTextModule.java <---- New Module
public class MyTextModule extends Module // New class
{
private String content;
}
Module.java
public class Module // <----- New parent class
{
protected String type;
}
How do I create a list of MyImageModule from myNewModule? I believe I need to use some kind of TypeAdapter from Gson library. But, I'm not familiar how to do this inside an existing response.
Use Map<String, MyImageModule>, in fact, a hashmap to solve the issue of non-list modules object in the json.
public static class MyNewModule {
public Map<String, MyImageModule> modules; // initialize as a hashmap
}

Using jackson deserialising a property which can be List of object or the object

My lib is calling an API which can return either of the following JSON structure -
{
"key_is_same" : {
"inner" : "val"
}
}
-or-
{
"key_is_same" : [{
"inner" : "val1"
},
{
"inner" : "val2"
}
]
}
Is there any annotation in jakson which can handle this and deserializ it into respective type
Looks like you are looking for the ACCEPT_SINGLE_VALUE_AS_ARRAY deserialization feature.
Feature that determines whether it is acceptable to coerce non-array (in JSON) values to work with Java collection (arrays, java.util.Collection) types. If enabled, collection deserializers will try to handle non-array values as if they had "implicit" surrounding JSON array. This feature is meant to be used for compatibility/interoperability reasons, to work with packages (such as XML-to-JSON converters) that leave out JSON array in cases where there is just a single element in array.
Feature is disabled by default.
It could be enabled either in ObjectMapper:
ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
Or via the #JsonFormat annotation:
#JsonFormat(with = Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
private List<Foo> oneOrMany;
For illustration purposes, consider the following JSON documents:
{
"oneOrMany": [
{
"value": "one"
},
{
"value": "two"
}
]
}
{
"oneOrMany": {
"value": "one"
}
}
It could be the deserialized to the following classes:
#Data
public class Foo {
private List<Bar> oneOrMany;
}
#Data
public class Bar {
private String value;
}
Just ensure the feature is enabled in your ObjectMapper or your field is annotated with #JsonFormat(with = Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY).
And in case you are looking for the equivalent feature for serialization, refer to WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED.
I would recommend using Object as your data type for the property which is dynamic. So Here is my sample.
import java.util.Arrays;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class MainObject {
private Object key_is_same;
public Object getKey_is_same() {
return key_is_same;
}
public void setKey_is_same(Object key) {
this.key_is_same = key;
}
public static class KeyObject {
private String inner;
public String getInner() {
return inner;
}
public void setInner(String inner) {
this.inner = inner;
}
}
public static void main(String...s) throws JsonProcessingException {
MainObject main = new MainObject();
KeyObject k = new KeyObject();
k.setInner("val1");
main.setKey_is_same(k);
ObjectMapper om = new ObjectMapper();
System.out.println(om.writeValueAsString(main));
main.setKey_is_same(Arrays.asList(k, k));
System.out.println(om.writeValueAsString(main));
public static void main(String...s) throws IOException {
MainObject main = new MainObject();
KeyObject k = new KeyObject();
k.setInner("val1");
main.setKey_is_same(k);
ObjectMapper om = new ObjectMapper();
System.out.println(om.writeValueAsString(main));
main.setKey_is_same(Arrays.asList(k, k));
System.out.println(om.writeValueAsString(main));
// Deserialize
MainObject mainWithObject = om.readValue("{\"key_is_same\":{\"inner\":\"val1\"}}", MainObject.class);
MainObject mainWithList = om.readValue("{\"key_is_same\":[{\"inner\":\"val1\"},{\"inner\":\"val1\"}]}", MainObject.class);
if(mainWithList.getKey_is_same() instanceof java.util.List) {
((java.util.List) mainWithList.getKey_is_same()).forEach(System.out::println);
}
}
}
}
Output
{"key_is_same":{"inner":"val1"}}
{"key_is_same":[{"inner":"val1"},{"inner":"val1"}]}

rest service: cannot get whole data from #Comsumes() ( by javax.​ws.​rs.Comsumes )

I have a rest service by Java and the request that invokes the REST service contains a JSON object.
I found sub_array_1 and sub_array_2 were empty Lists but other class members have their values in receviedObj.
Does #Consumes() cannot parse more than 1 level json object ?
How could I get correct data in sub_array_1 and sub_array_2 ?
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
/* ... */
#POST
#Path("")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response sendRequest(ClassB receviedObj) {
/* ... */
}
json object likes:
{
"item_1": "value_1",
"item_2": "value_2",
"item_3": "value_3",
"otherItems": [
{
"subitem_1": "subvalue_1",
"subObject": {
"name": "aaabbb",
"sub_array_1": [
{
"data_1": "d11",
"data_2": "d12",
"data_3": "d13"
},
{
"data_1": "d21",
"data_2": "d22",
"data_3": "d23"
}
],
"sub_array_2": [
{
"tag_1": "v1",
"tag_2": "v2",
"tag_3": "v3",
"tag_4": "v4"
}
]
}
}
]
}
java class:
public class ClassB {
public String item_1;
public String item_2;
public String item_3;
public List<otherItems> otherItems;
}
public class otherItems{
public String subitem_1;
public subObject subObject;
public otherItems(){
this.subitem_1 = "";
this.subObject = new subObject();
}
// ================================
public static class subObject{
public String name;
public List<sub_array_1> sub_array_1;
public List<sub_array_2> sub_array_2;
public subObject(){
this.name= "";
this.sub_array_1 = new ArrayList<sub_array_1>();
this.sub_array_2 = new ArrayList<sub_array_2>();
}
}
// =========================================
public static class sub_array_1 {
public String data_1;
public String data_2;
public String data_3;
public String getdata_1() {
return data_1;
}
public String getdata_2() {
return data_2;
}
public String getdata_3() {
return data_3;
}
}
public static class sub_array_2 {
public String tag_1;
public String tag_2;
public String tag_3;
public String tag_4;
public String gettag_1() {
return tag_1;
}
public String gettag_2() {
return tag_1;
}
public String gettag_3() {
return tag_1;
}
public String gettag_4() {
return tag_1;
}
}
}
I do not think the JSON you are sending is appropriate for ClassA as it has some params which are not there in ClassA. Params like item_1, item_2 etc. Per my test, following JSON should populate ClassA fine.
{
"subitem_1": "subvalue_1",
"subObject": {
"name": "aaabbb",
"sub_array_1": [
{
"data_1": "d11",
"data_2": "d12",
"data_3": "d13"
},
{
"data_1": "d21",
"data_2": "d22",
"data_3": "d23"
}
],
"sub_array_2": [
{
"tag_1": "v1",
"tag_2": "v1",
"tag_3": "v1",
"tag_4": "v1"
}
]
}
}
So, either you need to change ClassA to incorporate other fields or you need to use above JSON. Also, I suggest some reading on coding practices and naming conventions for Java
Finally I still cannot figure out why JSX-RS cannot convert JSON to java class correctly.
I use Gson to do the conversion and get the object with correct data.

Is it possible to get JsonRootName of nested child with Jackson?

I have nested objects that I want to get the root name from when I serialize it to json using jackson. this is the result I want(I apologize to all the flower enthusiasts but just needed a example, this is not to be interpreted as accurate data):
{
"plants": "flowers",
"types": {
"rose" : {
"color": "red",
"height": 25,
}
}
}
I got 2 classes, one wrapper class:
public class JsonWrapper {
public String plants = "flowers";
public Object types;
}
and the "flower" class:
#JsonRootName("rose")
public class rose{
public String color = "red";
public int height = 25;
}
now what I do is this:
JsonWrapper wrapper = new JsonWrapper();
wrapper.types = new rose();
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
String jsonInString = mapper.writeValueAsString(wrapper);
The result i get is:
{
"JsonWrapper":{
"plants": "flowers",
"types": {
"color": "red",
"height": 25,
}
}
}
So i get the root name for the wrapper object that is not annotated but not for the child object that is annotated. is there a way to tell jackson not to get a root name where there is none and also analyze child objects?
An alternate solution without JsonRootName.
JsonWrapper.java
import java.util.HashMap;
import java.util.Map;
public class JsonWrapper {
public String plants = "flowers";
Map<String, Flower> types = new HashMap<>();
public Map<String, Flower> getTypes() {
return types;
}
public void setTypes(Map<String, Flower> types) {
this.types = types;
}
}
Flower.java
public class Flower {
public String color = "red";
public int height = 25;
}
Main.java
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Main {
public static void main(String[] args) throws JsonProcessingException {
JsonWrapper wrapper = new JsonWrapper();
wrapper.getTypes().put("rose", new Flower());
ObjectMapper mapper = new ObjectMapper();
String jsonInString = mapper.writeValueAsString(wrapper);
System.out.println(jsonInString);
}
}

How to deserialize a keyless array with GSON?

I like to use GSON to deserialize the following JSON String.
{
"type": "FeatureCollection",
"features": [
{
"id": "FSROGD.4440181",
"geometry": {
"type": "Point",
"coordinates": [
16.7594706041998,
43.148716514354945
]
}
}
]
}
I already prepared the neccessary Java classes named Response, Features, Geometry and Coordinates. Besides the last class everything works fine. But for Coordinates, I do not understand what I should write since there are no keys given that I could prepare as member variables.
Here are the parent Geometry class ...
package info.metadude.trees.model.vienna;
import com.google.gson.annotations.SerializedName;
public class Geometry {
#SerializedName("type")
public String type;
// TODO: Prepare Coordinates class for GSON.
// #SerializedName("coordinates")
// public Coordinates coordinates;
}
... and the empty Coordinates class.
package info.metadude.trees.model.vienna;
public class Coordinates {
// TODO: No idea what should be defined here.
}
You could use coordinates as a collection property in Geometry. This would automatically map the values to the right property.
import java.util.List;
import com.google.gson.Gson;
public class GSonTest {
public static void main(final String[] args) {
Gson gson = new Gson();
System.out.println(gson.fromJson("{ \"type\": \"Point\", \"coordinates\": [ 16.7594706041998, 43.148716514354945 ] }", Geometry.class));
}
public static class Geometry {
List<Float> coordinates;
public List<Float> getCoordinates() {
return coordinates;
}
public void setCoordinates(final List<Float> coordinates) {
this.coordinates = coordinates;
}
#Override
public String toString() {
return "Geometry [coordinates=" + coordinates + "]";
}
}
}

Categories