I am using Jackson 2.2 to read a very large JSON string into a Java object. Using ObjectMapper, I read everything into the memory and transform the JSON string to object. This is all happening in memory, so the entire JSON string is loaded into the memory and transformed into the object.
If there a more memory efficient way of doing it? i.e. without loading the entire JSON string into the memory, I should still be able to load the object.
Yes, you typically use so-called "streaming" API to iterate over JSON tokens; and once positioned over first token of the value you want (START_OBJECT for JSON Objects), use data-binding API, passing reader/parser for it to use. Details of this depend on library. I know that at least following support this mode of operation:
Jackson
Gson
Genson
For Jackson, basic Streaming API usage is talked about here (for example); but one thing that does not show is how to bind objects once you are positioned at the right place.
So assuming JSON like:
{ "comment" : "...",
"values" : [
{ ... value object 1 ... },
{ ... value object 2. ... }
]
}
you could do:
ObjectMapper mapper = new ObjectMapper();
JsonParser jp = mapper.getFactory().createJsonParser(jsonInput);
jp.nextToken(); // will return START_OBJECT, may want to verify
while (jp.nextValue() != null) { // 'nextValue' skips FIELD_NAME token, if any
String fieldName = jp.getCurrentName();
if ("values".equals(fieldName)) {
// yes, should now point to START_ARRAY
while (jp.nextToken() == JsonToken.START_OBJECT) {
ValueObject v = mapper.readValue(jp, ValueObject.class);
// process individual value in whatever way to you want to...
}
} else if ("comment".equals(fieldName)) {
// handle comment?
} // may use another else to catch unknown fields, if any
}
jp.close();
and that should let you only bind one object at a time.
Related
I have following json as string:
{
"field1":"value1",
"field2":"value2",
"field3":{
"field31":"value31",
"field32":"value32"
},
"field4":{
"field41":"value41"
}
}
What is the best and the most modern way to get from this json just value from field41, so I would return "value41". I know that I can use JSONObject but I'm wondering weather we have any other better option?
Try JSONPath
String json = "...";
String field41 = JsonPath.read(json, "$.field4.field41");
You can test it here - https://jsonpath.herokuapp.com/
If you want to generate a real object out of it you can use Gson. You need to describe the class first. There are online json to Java objects converters out there. And then you can just call:
YourObject obj = new Gson().fromJson(json,YourObject.class);
System.out.println(obj.getField4().getField41());
And there you have it!
My question is the following, I can receive a JSON, where inside it can come two types of class "CHANGE" or "WITHDRAW" in the same type of request. Below is an example JSON 1 and JSON 2
JSON 1
{
"name":"Eduard Jack",
"change":{
"agency":"3213"
}
}
JSON 2
{
"name":"john Stev",
"withdraw":{
"documentNumber":"121212"
}
}
When I make this request I get a string from json where I make a mapper to convert into an object, in the OPENAPI documentation it tells me that it is oneOf, it can be one or the other, never both together. How can I make the code understand which class to deserialize into in the Java 11?
I think there are multiple ways to do so
This will convert you string into JsonNode where JSON1 is the string provided
JsonNode json = mapper.readTree(JSON1);
if (json.get("withdraw") == null) : //the value of withdraw will be null in JSON1
JsonParser parser = mapper.treeAsTokens(json);
Change change= mapper.readValue(parser, Change.class);
else: //the value of withdraw wont be null in
JsonParser parser = mapper.treeAsTokens(json);
Withdraw withdraw= mapper.readValue(parser, withdraw.class);
I have the following programming requirement:
problem:
Given two JSONs A and B, if the fields x,y,z in JSON A match the fields i,o,p in B return true else false.
approach:
I want to stay away from building a matching engine that depends on the json's format. I don't want to format the jsons by using pojos and then do object matching. My approach is to convert all the jsons into a hash map and then specify the location of the fields by using a string:
Example:
money -> a,b,c
{
a :
{
b : {
c: {
money : "100"
}
}
}
}
However this approach seems to be a bit tricky as we have to take into account collections. I have to cover all of the edge cases. Is there any spring library or java tool I can use to fulfill this purpose?.
There are many libraries being used for this purpose.The most popular one is com.google.gson
Usage:
JsonObject jo = (JsonObject)(jsonParser.parse("{somejsonstring}");<br>
jo.has("objectProperty") //Check if property exists
jo.get("objectProperty") // returns JsonElement,
jo.get("objectProperty").isJsonArray() // check if the property is the type that want
jo.getAsJsonArray("objectProperty") get the property
You may simplify this work by using im.wilk.vor:Voritem library gitHub or in Maven repository.
JsonElement je_one = jsonParser.parse("{some_json_string"})
JsonElement je_two = jsonParser.parse("{other_json_string"})
VorItem vi_one = vorItemFactory.from(je_one);
VorItem vi_two = vorItemFactory.from(je_two);
if (vi_one.get("a.b.c").optionalLong().isPresent() ) {
return vi_one.get("a.b.c").optionalLong().equals(vi_one.get("i.o.p").optionalLong())
}
return false;
I have a text file as input which contains Employees. Now I need to refactor the code and the JSON can either contain an Employee[] array or a Building[] array. I am using Jackson, and there are enums in my Java class.
{
Employee[]
}
{
Building[]
}
I have code to selectively parse each document, but how can the code detect whether it is an Employee doc or a Building doc?
I know it's kind of a bad design, but there are some constraints for which I am doing so.
I need something like this:
boolean isBuildingDoc(String json);
boolean isEmployeeDoc(String json);
How can I do this?
My advice would be to add a top level property to your json called 'info'.
For example:
{
"info": {
"document_type": "employee"
},
"content": {
// rest of your json goes here...
}
}
Put the old json you used to generate in 'content'. Then, when you parse your json file, you can easily check the info.document_type flag to see what document type you are working with.
However, if you do not have control over the json that is being parsed (e.g. if it is being sent from another program), then this approach will not work.
You can use tree modal of jackson to detect Employee or Building node.
E.g.
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(jsonString);
if(node.get("Employee") != null){
//handle it according to employee
}
else if(node.get("Building ") != null){
//handle it according to building
}
Note : Do remember one thing, get method searches for field in child elements also, So if your Employee array contains Building field as a child element, then this method will not work.
I am working on a GWT app that is receiving a JSON string, and I'm having a hard time getting down to the values of each object. I'm trying to transfer the incoming JSON string into an array of objects.
Here is the JSON (from Firebug response tab), The "d" is a .NET thing (Web Service Being Consumed is C#.
{
"d": [
{
"__type": "Event",
"ID": 30,
"Bin": 1,
"Date": "\/Date(1281544749000)\/",
"Desc": "Blue with white stripes.",
"Category": "1"
},
{
"__type": "Event",
"ID": 16,
"Bin": 3,
"Date": "\/Date(1281636239000)\/",
"Desc": "Yellow with pink stripes",
"Category": "1"
}
]
}
I'm trying to parse the JSON into objects, and then insert them into an array. I'm able to use Window.alert and get the entire "d" object to echo. However, when I try to access the elements of the array, GWT debugger just crashes.
//My GWT array to receive JSON Array
ArrayList<Item> itemInfo = new ArrayList<Item>();
//Getting response JSON into something I can work with.(THIS FAILS)
JSONArray jsonValue = JSONParser.parse(incomingJsonRespone);
//Just trying to verify I'm getting values
for (int i=0; i<jsonValue.size(); i++) {
JSONValue jsonItem = = JsonValue.get(i).getString();
Window.alert(jsonItem);
itemInfo.add(jsonItem);
}
I think I have narrowed down the problem to where the JSONArray instance is being created. Is there something blatantly wrong with how I'm trying to do this, because I'm not getting much help in the way of error messages?
In response to RMorrisey's comment:
Actually, it's more convoluted :/ It would look something like this (code untested, but you should get the general idea):
JSONValue jsonValue;
JSONArray jsonArray;
JSONObject jsonObject;
JSONString jsonString;
jsonValue = JSONParser.parseStrict(incomingJsonRespone);
// parseStrict is available in GWT >=2.1
// But without it, GWT is just internally calling eval()
// which is strongly discouraged for untrusted sources
if ((jsonObject = jsonValue.isObject()) == null) {
Window.alert("Error parsing the JSON");
// Possibilites: error during download,
// someone trying to break the application, etc.
}
jsonValue = jsonObject.get("d"); // Actually, this needs
// a null check too
if ((jsonArray = jsonValue.isArray()) == null) {
Window.alert("Error parsing the JSON");
}
jsonValue = jsonArray.get(0);
if ((jsonObject = jsonValue.isObject()) == null) {
Window.alert("Error parsing the JSON");
}
jsonValue = jsonObject.get("Desc");
if ((jsonString = jsonValue.isString()) == null) {
Window.alert("Error parsing the JSON");
}
Window.alert(jsonString.stringValue()); // Finally!
As you can see, when using JSONParser you have to/should be very cautious - that's the whole point, right? To parse an unsafe JSON (otherwise, like I suggested in the comments, you should go with JavaScript Overlay Types). You get a JSONValue, check if it's really what you think it should be, say, a JSONObject, you get that JSONObject, check if it has the "xyz" key, you get a JSONValue, rinse and repeat. Not the most interesting work, but at least its safer than just calling eval() on the whole JSON :)
Attention: as Jason pointed out, prior to GWT 2.1, JSONParser used eval() internally (it only had a parse() method - GWT 2.0 javadocs vs GWT 2.1). In GWT 2.1, parse() became deprecated and two more methods were introduced - parseLenient() (uses eval() internally) and parseStrict() (the safe approach). If you really have to use JSONParser, then I'd suggest upgrading to GWT 2.1 M2, because otherwise you might as well use JSOs. As an alternative to JSONParser for untrusted sources, you could try integrating json2.js as a JSON parser via JSNI.
PS: cinqoTimo, JSONArray jsonValue = JSONParser.parse(incomingJsonRespone); obviously doesn't work because JSONParser.parse has a return type of JSONValue, not JSONArray - didn't your IDE (Eclipse + Google Plugin?) warn you? Or at least the compiler.
It looks like you don't have an array, but a single root object, whose property called 'd' is an array. I'm not familiar with that specific API, but maybe you can try retrieving a JSONObject or similar instead of an array?