I have Json which can look like this:
{
"workshop_name" : "ABC"
"user_name" : "DEF"
}
In my app workshop_name is not mandatory, so it can came in minimal version:
{
"user_name" : "DEF"
}
Now I was thinking about using Java8 Optional to get workshop_name from JSON. I was using org.json library and JSONObject. I could easily check optional like this:
public static EnrichContext createEnricher(JSONObject json) {
EnrichContext enrichContext = new EnrichContext();
enrichContext.setWorkshopName(Optional.ofNullable(json.getString("workshop_name")).orElse("DEFAULT"));
enrichContext.setUserName(json.getString("user_name"));
}
I was forced to switch to GSON where it looks a little bit different.
json.get("workshop_name").getAsString();
This means that I have a new object in the middle after calling get on JsonObject (from GSON).
I tried to use nested Optional check, but it looks just too complex.
What I figured out is:
enrichContext.setWorkshopName((Optional.ofNullable(json.get("workshop_name")).orElse(new JsonPrimitive("DEFAULT"))).getAsString());
I don't like an idea of creating new JsonPrimitive on every read. Is there more optimal way for that issue?
What you could do is use a Optional<String> instead of a Optional<JsonPrimitive>
String workshopName = Optional.ofNullable(json.get("workshop_name"))
.map(JsonElement::getAsString)
.orElse("DEFAULT");
Related
I am creating a JSON using the Jackson JsonGenerator approach and everything seems to work perfectly fine apart from a minor glitch. I would like to move the particular key present in the created JSON to the top of the JSON.
I am creating a key schema which appears at the bottom of the JSON. I would like to know if there is a way to move it to the top of the JSON after finished creating the JSON.
Following is the JSON that I am creating:
public class JacksonTest {
public static void main(String[] args) throws IOException {
StringWriter jsonObjectWriter = new StringWriter();
JsonGenerator jsonGenerator = new JsonFactory().createGenerator(jsonObjectWriter).useDefaultPrettyPrinter();
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("a", "Value-A");
jsonGenerator.writeStringField("c", "Value-C");
jsonGenerator.writeStringField("b", "Value-B");
jsonGenerator.writeStringField("schema", "2.0");
jsonGenerator.close();
jsonGenerator.flush();
System.out.println(jsonObjectWriter.toString());
}
}
Following is the output I am getting:
{
"a" : "Value-A",
"c" : "Value-C",
"b" : "Value-B",
"schema" : "2.0"
}
I would like to convert the JSON something like this:
{
"schema" : "2.0",
"a" : "Value-A",
"c" : "Value-C",
"b" : "Value-B"
}
I would like to fetch the schema from my created JSON and add it to the top of the JSON.
Please Note:
I am aware the JSON order does not matter but I am doing this for better readability purposes. If there is a way then it would be really useful for the reader to understand the JSON better.
I am aware that I can create the schema at first in this code but this is just a sample application that I have provided for ease of understanding. In my real application, I have a Map that is populated dynamically throughout the execution and I am adding it at the end of the JSON creation. If I add at the first then I will miss out on a few of the values which are populated after creation so I am adding at the end but I want this to appear at the top of the JSON so trying to move to the top.
I want to know if there is a direct way to do it rather than looping over the JSON, as my created JSON in the real application can be pretty large.
I would really appreciate it if there was a way to do it or is there any workaround for this.
In my case, there might be different data type of same json field. Example:
"need_exp":1500
or
"need_exp":"-"
How to process this case? I know it can be processed by parse or use custom encoders, but this is a very complex json text, is there any way to solve that without rewriting the whole decoder (for example, just "tell" the decoder to convert all Int to String in need_exp field)?
It is called a disjunction which can be encoded with the Scala standard Either class.
Simply map the json that to the following class:
case class Foo(need_exp: Either[String, Int])
My solution is to use a custom decoder. Rewrite a little part of the JSON can be fine.
For example, there is a simple JSON:
{
/*many fields*/
"hotList":[/* ... many lists inside*/],
"list":[ {/*... many fields*/
"level_info":{
"current_exp":11463,
"current_level":5,
"current_min":10800,
"next_exp":28800 //there is the problem
},
"sex":"\u4fdd\u5bc6"},/*...many lists*/]
}
In this case, I don't need to rewrite the whole JSON encoder, just write a custom encoder of level_info:
implicit val decodeUserLevel: Decoder[UserLevel] = (c: HCursor) => for
{
current_exp <- c.downField("current_exp").as[Int]
current_level <- c.downField("current_level").as[Int]
current_min <- c.downField("current_min").as[Int]
next_exp <- c.downField("next_exp").withFocus(_.mapString
{
case """-""" => "-1"
case default => default
}).as[Int]
} yield
{
UserLevel(current_exp, current_level, current_min, next_exp)
}
and it worked.
Since my very first days of Java + JSON I tried to extract just some certain parts of a JSON.
But no matter if which of the libraries I used:
Gson
json-simple
javax.json
it never was possible to make it quick and comfortable. Mostly for easy task or even prototyping. It already cost me many hours of different approaches.
Going trough the hierarchy of an JSON
Object jsonObject = gson.fromJson(output, Object.class);
JsonElement jsonTree = gson.toJsonTree(jsonObject);
JsonArray commitList = jsonTree.getAsJsonArray();
JsonElement firstElement = commitList.get(0);
JsonObject firstElementObj = firstElement.getAsJsonObject();
System.out.println(firstElementObj.get("sha"));
JsonElement fileList = firstElementObj.get("files");
This is dirty code for a reason. It shows how many early approaches looks like and how many people cannot achieve it to do it better early.
Deserializing JSON to a Java Object
Your have to analyse the complete JSON to create an complete Java-Object representation just to get access to some single memebers of it. This is a way I never wanted to do for prototyping
JSON is an easy format. But using libraries like that is quite difficult and often an problem for beginner. I've found several different answers via Google and even StackOverflow. But most were quite big larged which required to create a own specific class for the whole JSON-Object.
What is the best approach to make it more beginner-friendly?
or
What is the best beginner-friendly approach?
Using Jackson (which you tagged), you can use JsonPointer expressions to navigate through a tree object:
ObjectMapper mapper = new ObjectMapper();
JsonNode tree = mapper
.readTree("[ { \"sha\": \"foo\", \"files\": [ { \"sha\": \"bar\" }, { \"sha\": \"quux\" } ] } ]");
System.out.println(tree.at("/0/sha").asText());
for (JsonNode file : tree.at("/0/files")) {
System.out.println(file.get("sha").asText());
}
You could also use the ObjectMapper to convert just parts of a tree to your model objects, if you want to start using that:
for (JsonNode fileNode : tree.at("/0/files")) {
FileInfo fileInfo = mapper.convertValue(fileNode, FileInfo.class);
System.out.println(fileInfo.sha);
}
If your target class (FileInfo) specifies to ignore unknown properties (annotate target class with #JsonIgnoreProperties(ignoreUnknown = true) or disable DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES on the mapper), then you can simply declare the properties you are interested in.
"Best" is whatever works to get you going.
Generate Plain Old Java Objects from JSON or JSON-Schema
One little helper I found via my research was an Online-Tool like
http://www.jsonschema2pojo.org/
This is a little help, when you know about that. But the negative side I mentioned at point 2 is still there.
You can use JsonSurfer to selectively extract value or object from big json with streaming JsonPath processor.
JsonSurfer jsonSurfer = JsonSurfer.gson();
System.out.println(jsonSurfer.collectOne(json, "$[0].sha"));
System.out.println(jsonSurfer.collectOne(json, "$[0].files"));
I'm a beginner of Scala, and I have JSON data formatted like below:
{
"index_key": {
"time":"12938473",
"event_detail": {
"event_name":"click",
"location":"US"
}
}
}
I'm trying to get the content of "index_key" and extract the content of second level as a new JSON objet and initiate a class based on the second level data.
{
"time":"12938473",
"event_detail": {
"event_name":"click",
"location":"US"
}
}
I tried to use json4s to extract from the above json to be a Event class, but how to get rid of the "index_key" which is the first level key?
case class Detail(event_name: String, location: String)
case class Event(time: String, event_detail: Detail)
json.extract[Event]
I've read json4s documentation, and also http://www.scala-lang.org/api/2.10.3/index.html#scala.util.parsing.json.JSON$, but still don't quite get it, as it seems the pre-defined json should be fit for the parser?
Could anyone please tell me how to get the second level data (or any lower level) of the json structure?
You can use \ to get to the object you want to extract:
val json = parse(str) \ "index_key"
json.extract[Event]
I'd like to know the most simple way to detect if a key/field exists in a JSON String.
for example:
if(jsonObject(myJsonString).hasKey("myKey")){
}
I would not prefer to write a lot. I am currently using minimal JSON and it appears it does not have such a function.
Answer:
JSONObject jsonObj2 = new JSONObject(message);
if(jsonObj2.has("key"));
Not sure what you mean exactly by minimal JSON, personally I find the org.json package simple and straightforward (i.e. minimal overhead). It is found here. The org.json.JSONObject class, for example, contains the public boolean has(String key) method, which is used to check if a certain key exists.
In minimal-json, you'd write:
if (JsonObject.readFrom(myJsonString).get("myKey") != null) {
...
}
I faced the same problem.
obj.has("myKey") was not working for minimalJson.
My solution:
Take your JsonObject obj which has that key and then do the following:
if(obj.get("myKey") != null)