What's the complexity of getJSONObject and getJSONArray methods? - java

I'm using org.json library as JSON-client for my Java application and I would like to know the complexity of some methods from this lib.
I'm retrieving thousands of JSON objects inside a JSON array inside another JSON objects (and so on) from a database via it's HTTP API. As an example (and only as an example, my case is much more complex), suppose that I'm doing something like that:
// Ignoring attributes types
import org.json.*;
public static void main(String[] args) {
response = MyHTTPClient.post(url, query).asJSON();
response = JSON.parse(response);
data = response.getJSONObject(1).getJSONArray("results").getJSONObject(0);
}
What's the complexity of getJSONObject(int) and getJSONArray(String) methods from org.json library? Is it running in a constant [O(1)] or linear [O(n)] time? If none, what's the correct answer?

org.json will parse the entire JSON document when you instantiate the JSONObject from a string (or JSONTokener). The getJSONObject() and getJSONArray() methods are just typed versions of the untyped get() methods (which return Object instance). if you look at the source you can see that JSONObject uses a HashMap while JSONArray uses an ArrayList for internal representations, so the execution times are close-to-constant (O(1))

Both getJSONArray and getJSONObject and methods eventually call opt(String paramString) method which gets value from a HashMap. So they should work in close to constant time i.e. O(1) ideally. Here's a code snippet:
public Object opt(String paramString)
{
return paramString == null ? null : map.get(paramString);
}
You can look at the source code yourself and dig in.

Related

javax.json objects have same methods, but they're not implementations of a common interface. How to cast?

I'm dealing with the strange javax.json library. So here's the problem:
I need to cast an Object of type JsonValue to either JsonObject or JsonArray so I can call the methods getJsonObject and getJsonArray of it. Both JsonArray and JsonObject have the same method names with the same functionalities but they're not implemented methods, they are methods defined on each of them! See: JsonObject, JsonArray.
The obvious solution would be to verify the type and then cast depending on the verified type, like this:
if (current.getValueType().equals(JsonValue.ValueType.OBJECT)) {
current = ((JsonObject) current).getJsonObject(node);
} else if (current.getValueType().equals(JsonValue.ValueType.ARRAY)) {
current = ((JsonArray) current).getJsonObject(node);
}
but it'd require too many repetitions on my code. So I ask:
1) If both JsonObject and JsonArray have the same methods, why they're not implementations of some interface?
2) Is there a more elegant way to cast the object to JsonObject or JsonArray at the same time by using some trick? Do you know any way to make this situation better?
Although the 2 methods on the 2 different objects have the same name, their signatures are in fact different. JsonObject#getJsonObject(String) accepts a String key identifying the value to pull from a JSON object of key-value pairs. JsonArray#getJsonObject(int) accepts an int index identifying which element to pull the value from in a JSON array.
In this case, there is no appropriate common interface that the 2 classes can share. Your code will have to know whether to inspect a JSON object or a JSON array and cast accordingly.
Since the 2 methods in question do not have the same signature, there are not other alternatives for calling them in a "common way". You could potentially use reflection, but this risks making the code more confusing. For example, Apache Commons includes MethodUtils#invokeMethod. You could potentially use that to invoke any method named "getJsonObject", accepting any kind of object (either String or int). Although using this would make it "common code" across both cases, it's potentially confusing for people reading the code later. They'd have to keep track of the fact that this is using reflection, and that the passed argument might be either String or int, and that it really all works out thanks to it being either a JSON object or array. Instead, I would favor just doing the downcast in this case.
Chris is right, Your code will have to know whether to inspect a JSON object or a JSON array and cast accordingly. However, if you are ok with adding an external library, I would recommend gson for parsing Json
This library has JsonElement class which should fit good in your case. look at this to see how it works

rest-assured jsonPath returns HashMap instead of LinkedHashMap

This pertains to Java.
I would like to be able to change the default behavior of how a JsonPath object returns itself when parsed from a json response so that I can still leverage the methods it comes with such as getMap(), getList(), etc. Ideally I would like all the JsonPath methods to return their Map objects as a LinkedHashMap instead of a HashMap or at the minimum have the getMap() method return as a LinkedHashMap so I can preserve key ordering.
The below response object's json key ordering matches the browser's json response:
Response response = given().get(urlQuery).then().extract().response();
However, when you attempt to grab an object or value from the response via jsonPath() then the json key ordering is all screwed up due to the fact that JsonPath methods are leveraging a HashMap instead of a LinkedHashMap behind the scenes such as the code snippet below does:
Map map = response.jsonPath().getMap("path.to.a.map");
I'm hoping the answer lies within changing the config to something, or overloading a method somewhere, etc. as I like using the rest-assured library for all my json parsing except I now need to preserve key ordering.
Aside from the response object as mentioned above, I would be content if I could at the minimum get the JsonPath methods to return the json in the correct order as shown by the below code example:
import com.jayway.restassured.path.json.JsonPath;
String json = "{\"fields\":{\"field1\":1,\"field2\":2,\"field3\":3,\"field4\":\"4\"}}";
// The value of the JsonPath object stays in the correct order: {"fields":{"field1":1,"field2":2,"field3":3,"field4":"4"}}
JsonPath jsonpath = new JsonPath(json);
// When using any of the JsonPath methods the order is messed up and returns: "{field4=4, field3=3, field2=2, field1=1}"
Object map = jsonpath.getMap("fields");
I would like to somehow get the JsonPath methods to keep the order by leveraging LinkedHashMap types but am unsure how or where to implement this.

Elegant mapping from POJOs to vertx.io's JsonObject?

I am currently working on a vertx.io application and wanted to use the provide mongo api for data storage. I currently have a rather clunky abstraction on top of the stock JsonObject classes where all get and set methods are replaced with things like:
this.backingObject.get(KEY_FOR_THIS_PROPERTY);
This is all well and good for now, but it won't scale particularly well. it also seems dirty, specifically when using nested arrays or objects. For example, if I want to be able to fill fields only when actual data is known, I have to check if the array exists, and if it doesn't create it and store it in the object. Then I can add an element to the list. For example:
if (this.backingObject.getJsonArray(KEY_LIST) == null) {
this.backingObject.put(KEY_LIST, new JsonArray());
}
this.backingObject.getJsonArray(KEY_LIST).add(p.getBackingObject());
I have thought about potential solutions but don't particularly like any of them. Namely, I could use Gson or some similar library with annotation support to handle loading the object for the purposes of manipulating the data in my code, and then using the serialize and unserialize function of both Gson and Vertx to convert between the formats (vertx to load data -> json string -> gson to parse json into pojos -> make changes -> serialize to json string -> parse with vertx and save) but that's a really gross and inefficient workflow. I could also probably come up with some sort of abstract wrapper that extends/implements the vertx json library but passes all the functionality through to gson, but that also seems like a lot of work.
Is there any good way to achieve more friendly and maintainable serialization using vertx?
I just submitted a patch to Vert.x that defines two new convenience functions for converting between JsonObject and Java object instances without the inefficiency of going through an intermediate JSON string representation. This will be in version 3.4.
// Create a JsonObject from the fields of a Java object.
// Faster than calling `new JsonObject(Json.encode(obj))`.
public static JsonObject mapFrom(Object obj)
// Instantiate a Java object from a JsonObject.
// Faster than calling `Json.decodeValue(Json.encode(jsonObject), type)`.
public <T> T mapTo(Class<T> type)
Internally this uses ObjectMapper#convertValue(...), see Tim Putnam's answer for caveats of this approach. The code is here.
I believe Jackson's ObjectMapper.convertValue(..) functions don't convert via String, and Vert.x is using Jackson for managing JsonObject anyway.
JsonObject just has an underlying map representing the values, accessible via JsonObject.getMap(), and a Jackson serializer/deserializer on the public ObjectMapper instance in io.vertx.core.json.Json.
To switch between JsonObject and a data model expressed in Pojos serializable with Jackson, you can do:
JsonObject myVertxMsg = ...
MyPojo pojo = Json.mapper.convertValue ( myVertxMsg.getMap(), MyPojo.class );
I would guess this is more efficient than going via a String (but its just a guess), and I hate the idea of altering the data class just to suit the environment, so it depends on the context - form vs performance.
To convert from Pojo to JsonObject, convert to a map with Jackson and then use the constructor on JsonObject:
JsonObject myobj = new JsonObject ( Json.mapper.convertValue ( pojo, Map.class ));
If you have implied nested JsonObjects or JsonArray objects in your definition, they will get instantiated as Maps and Lists by default. JsonObject will internally re-wrap these when you access fields specifying those types (e.g. with getJsonArray(..).
Because JsonObject is freeform and you're converting to a static type, you may get some unwanted UnrecognizedPropertyException to deal with. It may be useful to create your own ObjectMapper, add the vertx JsonObjectSerializer and JsonArraySerializer, and then make configuration changes to suit (such as DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES in Jackson).
Not sure if I've understood you correctly, but it sounds like you're trying to find a simple way of converting POJOs to JsonObject?
So, we have lots of pojos that we send over the EventBus as JsonObjects
I've found the easiest way is to use the vert.x Json class which has loads of helper methods to convert to / from Json Strings
JsonObject jsonObject = new JsonObject(Json.encode(myPojo));
Sometimes you need to add some custom (de)serializers, but we always stick with Jackson - that is what Vert.x is using so they work out of the box.
What we actually do, is provide an interface like the following:
public JsonObjectSerializable {
public JsonObject toJson();
}
And all our pojos that need to be sent over the EventBus have to implement this interface.
Then our EventBus sending code looks something like (simplified):
public <T extends JsonObjectSerializable> Response<T> dispatch(T eventPayload);
Also, as we generally don't unit test Pojos, adding this interface encourages the developers to unit test their conversion.
Hope this helps,
Will
Try this:
io.vertx.core.json.Json.mapper.convertValue(json.getMap(), cls)
I think that using Gson as you described is the best possible solution at the current time.
While I agree that if a protocol layer was included in Vert.x it would indeed be first prize, using Gson keeps your server internals pretty organised and is unlikely to be the performance bottleneck.
When and only when this strategy becomes the performance bottleneck have you reached the point to engineer a better solution. Anything before that is premature optimisation.
My two cents.
You can try:
new JsonObject().mapFrom(object)

Converting JSON Object(s) from file using Java

I have a JSON file with no clue on how data will be in it nor the structure of data.
The only thing known is that it will have either an array of JSON objects or a single JSON object.
I need to get each object from the file and store it as a separate item. In case of array of objects in the file, I should get an array of JSON strings which I can store in DB.
Basically, I need to read this file and separate out each JSON object from it and store it in DB as a string.
One of the ways to do it was to use JACKSON ObjectMapper and assign these items to a Hashmap as key value pairs, but I am not sure though how it can be done If there are list of JSON Objects in the file.
Sample JSON File:
[
{
"name":"Bob",
"type":"Email",
"from":"a#a.com",
"to":"b#B.com",
"attachments":[...],
.
.
.
}
]
Do you know the Object structure that the JSON has(let it be Array or a single one) ? If Yes,
First load the json string form the file into an in memory string.
check the string for Array existence, by searching for '[',']' in the outer structure of multiple occurrences of '{' or '}'
once you know whether you have an array or a single object, you can pass it as object reference to either Jackson or GSON parsers
create in memory Array of JsonObject.class say List. It is actually better to enclose this List inside another class. say myJsonObjects and have a List inside it.
Let us see GSON parsers (by google), though Jackson can also be used in the similar implementation
Gson gson = new Gson();
if(isArray){
myJsonObjects jsonArray = gson.fromJson(jsonStringFromFile,myJsonObjects );
}
else{
gson.fromJson(jsonStringFromFile,JsonObject);
}
http://google-gson.googlecode.com/svn-history/trunk/gson/docs/javadocs/com/google/gson/Gson.html
Jackson is my favorite JSON-to-POJO library. It doesn't really matter where you're loading the JSON from (a URL or from the filesystem), there are handlers for several input sources.
Here's an example:
Map<String,Object> userData = mapper.readValue(new File("user.json"), Map.class);
As far as having an unknown number of JSON structures that you're about to parse, the first thing that comes to mind is to have a mapper for each type you're expecting. You could then wrap the parsing code in try/catch blocks so that if the first fails with whatever exception Jackson gives you when encountering an unexpected format, you can then try the next format and so on.
If you're just trying to generically parse JSON that you don't know the structure of beforehand, you can try something like this:
mapper.readValue(jsonString, new TypeReference<List<EntryType>>() {});
The documentation for Jackson is pretty good-- giving it a solid read-through should definitely help. Here's a good five minute tutorial: http://wiki.fasterxml.com/JacksonInFiveMinutes
I prefer use Gson:
Gson gson;
Map<String, Object>parameters=gson.fromJson(myString);
the rest is iterate the map, i hope help you

Convert strings to Java objects automatically

I want to convert user input that comes as Map<String, String[]> to objects in Java. More specically I want to convert the params of a HttpServletRequest to the fields of an arbitrary domain object.
I'd like to have something like this:
Domain d = Converter.convert(params, new Domain());
If there is more than one element in the string array, which is the value of a map entry, it should be converted to a list or array. Maybe the locale should be considered for date and currency conversion. And a list of conversion errors would be nice.
Is there a library with such a converter?
Would you call it "converter"? I think it is often called "data binding", but that is the wrong term in my opionion, since it is related to binding model values to GUI elements, what is a slightly different thing - isn't it?
If your web framework does not support this functionality have a look at
http://commons.apache.org/beanutils/ ,espeically the beanutils package which has classes with similar purposes (maybe exactly the same) that you want.
You may also consider switching to a more mature framework ;-)
Don't use this plain code as it is only an example. You should add some pretty exception handling and a loop through a map. But generally the idea is like this:
void putValue(String name, String value, Object object) throws Exception {
String setterName = "set"+name.substring(0,1).toUpperCase()+name.substring(1);
Method m = object.getClass().getMethod(setterName, String.class);
if (m!=null) {
m.invoke(object, value);
}
}
This code, given a parameter name 'name' will try to find a method setName(String name) and call it with the given value.

Categories

Resources