GSON deserialize/serialize hierarchy class - java

I have a java app that send json content to my server (c++). I my server i receive the json, do the parse, the validation, etc and send back the response with json too.
I have one request in my java app that have this json body (example):
{
"a": "a",
"b": "b",
"searchMethod": {
"searchByUser": {
"userId": "userId"
}
}
}
But for the same command i can have other searchMethod:
{
"a": "a",
"b": "b",
"searchMethod": {
"searchByEmail": {
"email": "user#user.com"
}
}
}
So, when the user do the request we can send to my server one of this two different json bodys. I never know what searchMethod we send. This part (check what searchMethod the user send, etc), i do in my c++ server when i receive the json. So in my java app i only need to use the gson to send a searchMethod object with their content.
This my class to do the request:
public class RequestExample implements SerializableJSON
{
public String a;
public String b;
public RequestExample(String a, b)
{
this.a = a;
this.b = b;
}
public static RequestExample fromStringJson(String data)
{
try
{
Gson gson = new Gson();
return gson.fromJson(data, RequestExample.class);
}
catch(Exception e)
{
return null;
}
}
public static RequestExample fromBytesJson(byte[] data)
{
if (data == null) return null;
try
{
String str = new String(data, "utf-8");
return fromStringJson(str);
}
catch (Exception e)
{
return null;
}
}
#Override
public String toJsonString()
{
try
{
Gson gson = new Gson();
return gson.toJson(this);
}
catch(Exception e)
{
return null;
}
}
#Override
public byte[] toJsonBytes()
{
try
{
return this.toJsonString().getBytes("utf-8");
}
catch (Exception e)
{
return null;
}
}
}
I already implement the fields a and b because its always the same in this request. In this class the fromStringJson(String data) receive the data string field that contain all json that the user try to send. In this function i use the gson.fromJson to convert this string to a json object type of my RequestExample class.
So the main question is: How to adapt my RequestExample class to convert the string to a json object regardless of the type of searchMethod. Like i said in my java app i dont need to know how seachMethod the user choose. In my server yes, but this part i already implement. So for now, i only need to send the request to my server.

If you don't use field searchMethod, you can implement it like a Map
private Map<String, Object> searchMethod = new HashMap<>();
or
private Map<String, Map<String,Object>> searchMethod = new HashMap<>();
or
private Map<String, Map<String,String>> searchMethod = new HashMap<>();

Related

Gson append object to json file

I am currently working on a todo web application using Spring Boot. The problem I'm facing is that whenever I add an item it is not stored in my json file. This is my current json file:
[
{
"id": 0,
"task": "some task"
},
{
"id": 1,
"task": "some other task"
},
{
"id": 2,
"task": "some different task"
}
]
When I add my todo item with the application, it gets added to my dataprovider;
TodoDataProvider.java:
public class TodoDataProvider {
private static TodoDataProvider instance;
private List<TodoItem> todoItems = new ArrayList<>();
public static TodoDataProvider getInstance() {
if (instance == null) {
instance = new TodoDataProvider();
}
//read data from json
Gson gson = new Gson();
try {
FileReader reader = new FileReader("src/main/java/com/example/servingwebcontent/todos.json");
TodoItem[] tempTodos = gson.fromJson(reader, TodoItem[].class);
for (TodoItem tempTodo : tempTodos) {
instance.addTodo(tempTodo);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return instance;
}
... getters and setters
After I try to add this todo my json file becomes empty. What is the best way to add this new json object to the existing json file using gson?
This is the code where I add this item:
TodoController.java
#Controller
public class TodoController {
TodoDataProvider dataProvider = TodoDataProvider.getInstance();
#GetMapping("/")
public String greeting(Model model) {
model.addAttribute("todos", dataProvider.getTodoItems());
return "todo";
}
#PostMapping("/")
public String addTodo(Model model, #RequestParam("todoTask") String todoTask) {
TodoItem todoItem = new TodoItem(4, todoTask);
dataProvider.addTodo(todoItem);
Gson gson = new Gson();
try {
// TODO: 14-7-2022 add to json instead of replace
gson.toJson(dataProvider.getTodoItems(), new FileWriter("src/main/java/com/example/servingwebcontent/todos.json"));
} catch (IOException e) {
System.out.println(e.getMessage());
}
model.addAttribute("todos", dataProvider.getTodoItems());
return "redirect:/";
}
}

Identify JsonObject vs JsonArray using Gson

I have the following validator which checks if a JSON string is valid using Gson. It works well with a JSON object but it blows up when you pass it a JSON array.
JsonStringValidator
public class JsonStringValidator implements ConstraintValidator<JsonString, String> {
private static final TypeAdapter<JsonObject> strictGsonObjectAdapter =
new Gson().getAdapter(JsonObject.class);
#Override
public boolean isValid(String jsonString, ConstraintValidatorContext context) {
try {
try (JsonReader reader = new JsonReader(new StringReader(jsonString))) {
strictGsonObjectAdapter.read(reader);
reader.hasNext();
return true;
}
} catch (IOException e) {
return false;
}
}
}
Works
{
"books":[
{
"isbn": "12345"
}
]
}
Fails
[
{
"isbn": "12345"
}
]
Exception
com.google.gson.JsonSyntaxException: Expected a com.google.gson.JsonObject but was com.google.gson.JsonArray
So it seems like I also need a strictGsonArrayAdapter.
But how can I determine if it's an array or object before calling strictGsonObjectAdapter?
I was able to determine whether the JSON string was an array or an object by using JsonParser to give me a JsonElement.
The JsonElement class has boolean methods for isJsonArray() and isJsonObject().
JsonElement jsonElement = JsonParser.parseString(jsonString);
log.info(jsonElement.isJsonArray());
log.info(jsonElement.isJsonObject());

Getting value from json item in java

I have a json file, for example:
{
"A":"-0.4",
"B":"-0.2",
"C":"-0.2",
"D":"X",
"E":"0.2",
"F":"0.2",
"J":"0.3"
}
I want return each element of a list json when I call it via my function.
I did a function to do this:
public JSONObject my_function() {
JSONParser parser = new JSONParser();
List<JSONObject> records = new ArrayList<JSONObject>();
try (FileReader reader = new FileReader("File.json")) {
//Read JSON file
Object obj = parser.parse(reader);
JSONObject docs = (JSONObject) obj;
LOGGER.info("read elements" + docs); // it display all a list of a json file like this: {"A":"-0.4","B":"-0.2","C":"-0.2","D":"X","E":"0.2","F":"0.2","J":"0.3"}
for (int i = 0; i < docs.size(); i++) {
records.add((JSONObject) docs.get(i));
System.out.println((records)); // it return null
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
LOGGER.info("The first element of a list is:" +records.get(0)); // return null
return records.get(0);
How can I change my function to return the value of each element in a json file.
For example, when I call my_function:
my_function.get("A") should display -0.4
Thank you
First you need a Class for mapping
public class Json {
private String a;
private String b;
private String c;
private String d;
private String e;
private String f;
private String j;
//getters and setters
}
Then in your working class
ObjectMapper mapper = new ObjectMapper();
//JSON from file to Object
Json jsn = mapper.readValue(new File("File.json"), Json.class);
then you can use that object in a usual way...
here is the dependency I used
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.3</version>
</dependency>
Reference
In Java you can use only class`s methods, as I know.
If you want to get your second element by its first, you should in your class create 2 methods like
class Main {
Map<String, String> records = new HashMap<>();
public JSONObject my_function() {
// your realization where you should insert your pairs into Map.
}
public String get(String firstElement){
return map.getValue(firstElement);
}
}
class someOtherClass {
Main main = new Main();
main .my_function();
main .get("A");
}

How to send a tuple to different bolt according to a value in the message

I have a Storm cluster connecting to Kinesis Stream. The message looks like this.
{
_c: "a"
}
or it should be
{
_c: "b"
}
I would like to send a tuple with _c="a" to one bolt and _c="b" to a different bolt. How do I achieve this?
This is the bolt that parsing the message from Kinesis to JSON Object using GSon
#Override
public void execute(Tuple tuple) {
String partitionKey = (String) tuple.getValueByField(SampleKinesisRecordScheme.FIELD_PARTITION_KEY);
String sequenceNumber = (String) tuple.getValueByField(SampleKinesisRecordScheme.FIELD_SEQUENCE_NUMBER);
byte[] payload = (byte[]) tuple.getValueByField(SampleKinesisRecordScheme.FIELD_RECORD_DATA);
ByteBuffer buffer = ByteBuffer.wrap(payload);
String data = null;
try {
data = decoder.decode(buffer).toString();
HashMap < String, String > map = new Gson().fromJson(data, new TypeToken < HashMap < String, Object >> () {}.getType());
this.outputCollector.emit(tuple, new Values(map));
this.outputCollector.ack(tuple);
} catch (CharacterCodingException e) {
this.outputCollector.fail(tuple);
}
}
Thanks
You can define two streams in your bolt and then declare two outputstreams :
#Override
public void execute(Tuple tuple) {
// ...
// Some Code
// ...
if (_c =="a") {
collector.emit("stream1", tuple, new Values(_c));
} else {
collector.emit("stream2", tuple, new Values(_c));
}
}
#Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
outputFieldsDeclarer.declareStream("stream1", new Fields("_c"));
outputFieldsDeclarer.declareStream("stream2", new Fields("_c"));
} }
In your topology you can then use the option in ShuffleGrouping to pass a Stream_id.
topology.setBolt("FirstBolt",new FirstBolt(),1);
topology.setBolt("newBolt1", new Custombolt(),1).shuffleGrouping("FirstBolt", "stream1");
topology.setBolt("newBolt2", new Custombolt(),1).shuffleGrouping("FirstBolt", "stream2");
Another possibility is to just send it to both bolts and then check the value in both bolts and execute the required code.

Android/java Parsing JSON with numbered data [duplicate]

This question already has answers here:
How to parse a dynamic JSON key in a Nested JSON result?
(5 answers)
Closed 7 years ago.
I have been looking for parsing JSON data in java/android. unfortunately, there is no JSON that same as mine. i have JSON data that include weird number, looks like :
{
"formules": [{"1":
{
"formule": "Linear Motion",
"url": "qp1"
},"2":
{
"formule": "Constant Acceleration Motion",
"url": "qp2"
},"3":
{
"formule": "Projectile Motion",
"url": "qp3"
}
}
]
}
Please help me how to parse this in Java/android. Thanks
try this
JSONObject jsonObject = new JSONObject(string);
JSONArray jsonArray = jsonObject.getJSONArray("formules");
JSONObject jsonObject1 = jsonArray.getJSONObject(0);
Now you can access object "1" as
JSONObject json = jsonObject1.getJSONObject("1");
or use iterator to iterate as below
Iterator keys = jsonObject1.keys();
while(keys.hasNext()) {
// loop to get the dynamic key
String currentDynamicKey = (String)keys.next();
JSONObject json = jsonObject1.getJSONObject(currentDynamicKey);
}
let me know if it works
For parsing Json in Android, I have found the Gson Library to be helpful
http://mvnrepository.com/artifact/com.google.code.gson/gson/2.3
What it would require is creating a pojo class that represents your object. Might look something like
public class ClassPojo
{
private Formules[] formules;
public Formules[] getFormules ()
{
return formules;
}
public void setFormules (Formules[] formules)
{
this.formules = formules;
}
#Override
public String toString()
{
return "ClassPojo [formules = "+formules+"]";
}
}
public class Formules
{
private Formule 3;
private Forumle 2;
private Formule 1;
}
public class Formule
{
private String formule;
private String url;
public String getFormule ()
{
return formule;
}
public void setFormule (String formule)
{
this.formule = formule;
}
public String getUrl ()
{
return url;
}
public void setUrl (String url)
{
this.url = url;
}
#Override
public String toString()
{
return "ClassPojo [formule = "+formule+", url = "+url+"]";
}
}
then to convert it to and from JSon,you could use
//Convert to JSON
ClassPojo pojo = new ClassPojo();
Gson gson = new Gson();
String json = gson.toJson(pojo);
//COnvert back to Java object
ClassPojo pojo = gson.fromJson(json,ClassPojo.class);

Categories