My sample JSON input is as follows:
"JobName":"Test Job 1",
"events":[
{ "features":[],
"InputHiveTable":"uilog_uiclientlogdata",
"eventColumn":"command",
"name":"edu.apollogrp.classroom.discussion.client.events.CreateDiscussionEvent"
},
Consider the field "InputHiveTable", it could be in all uppercase INPUTHIVETABLE, all lowercase inputhivetable, or a mixture of both as it is now.
Currently, I'm reading the field as follows (in Java):
JSONObject jsonObject = (JSONObject) obj;
JSONArray events = (JSONArray) jsonObject.get("events");
String InputHiveTable = (String)event.get("InputHiveTable");
So my question is how do I search for the field "InputHiveTable" while ignoring the case.
I'm using JSON Simple libraries.
If you have to perform this case-insensitive lookup many times, I'd just write a method to do that lookup:
public Object getIgnoreCase(JSONObject jobj, String key) {
Iterator<String> iter = jobj.keySet().iterator();
while (iter.hasNext()) {
String key1 = iter.next();
if (key1.equalsIgnoreCase(key)) {
return jobj.get(key1);
}
}
return null;
}
You could read the JSONObject into a java string, and call String.toLowerCase on it and store it back into a JSONObject. This will turn the entire case of the string to lower case, so you will have to account for that elsewhere in your logic. After that, you then would just have to do a get call on "inputhivetable".
By no means is it a pretty solution, but it is a potential work around if there is absolutely no other way for you to handle what you're returning as your JSON input.
Given that case-insensitivity can be achieved with TreeMap (i.e. via String.CASE_INSENSITIVE_ORDER comparator), you can probably do the following:
Implement your own MyJSONObject extending TreeMap where its methods will be just calling static methods of JSONObject with the same signatures and all required interfaces as in JSONObject. In default constructor write super(String.CASE_INSENSITIVE_ORDER)
Implement ContainerFactory interface where createObjectContainer will return new instance of MyJSONObject (and createArrayContainer will just return new JSONArray).
To run it with new container MyContainerFactory:
StringReader in = new StringReader(yourJSONString);
JSONParser parser = new JSONParser();
parser.parse(in, yourContainerFactory)
Related
I'm looking for a way to hide/mask the sensitive details of JSON output coming from a response, like account number.
All the answers I got over the web requires me to know the JSON structure before hand. Isn't there any way to extensively traverse each key and then replace it's value with required masking character, without knowing the JSON structure beforehand, which means the required key can be within a JSONArray or JSONObject and sometimes within one another.
Check if the following link to handle dynamic Json helps.
Basically the link highlights two options.
a) Using JsonNode
b) Mapping Dynamic properties using a Map
If you are using the com.google.gson.GsonBuilder.GsonBuilder(). You can add Type adapters, using the method registerTypeAdapter(TypeToAdapt.class, myTypeAdapter), where myTypeAdapter extends TypeAdapter<TypeToAdapt>.
Possibly more to your case, you can set exclusion classes, see:
https://howtodoinjava.com/gson/gson-gsonbuilder-configuration/
It is also possible to add bespoke Serialisers and deserialisers by using the #JsonAdapter(BespokeSerialiser.class) or #JsonAdapter(BespokeDeserialiser.class) to your model class.
The BespokeSerialiser or BespokeDeserialiser must implement JsonSerializer<ModelClass> or JsonDeserializer<ModelClass>.
Thank you all for the replies, it gave me an insight into the solution I was looking for. However, me and my colleague wrote the exact method we were looking for. The method we wrote accepts a JSON as an JSON Object, the key to be searched and the mask string by which I want the key's value to be replaced with.
Feel free to contribute on improving the below code.
public static JSONObject maskJSONValue(JSONObject jsonObject, String key, String mask) throws Exception{
Iterator iterator = jsonObject.keys();
String localKey = null;
while (iterator.hasNext()){
localKey = (String) iterator.next();
if((jsonObject.optJSONArray(localKey) == null) && (jsonObject.optJSONObject(localKey) == null)){
if((localKey.equals(key))){
jsonObject.put(localKey, mask);
return jsonObject;
}
}
}
if(jsonObject.optJSONObject(localKey) != null)
maskJSONValue(jsonObject.getJSONObject(localKey), key, mask);
if(jsonObject.optJSONArray(localKey) != null){
JSONArray jArray = jsonObject.getJSONArray(localKey);
for( int i = 0; i < jArray.length(); i++)
maskJSONValue(jArray.getJSONObject(i), key, mask);
}
return jsonObject;
}
Running a Play! app with Scala. I'm doing a request where the response is expected to be a JSON string. When checking the debugger, the JsonElement returns OK with all information as expected. However, the problem is when I try to actually run methods on that JsonElement.
val json = WS.url("http://maps.googleapis.com/maps/api/geocode/json?callback=?&sensor=true&address=%s", startAddress+","+startCity+","+startProvince).get.getJson
val geocoder = json.getAsString
The only error I get back is Unsupported Operation Exception: null and I've tried this on getAsString and getAsJsonObject and getAsJsonPrimitive
Any idea why it's failing on all methods? Thanks.
I had a similar problem and I had to change jsonObject.getAsString() to jsonObject.toString();
Maybe your JsonElement is a JsonNull
What you could do is to first check that it isn't by using json.isJsonNull
Otherwise, try to get its String representation with json.toString
In my case I just needed to get the element as an empty string if it is null, so I wrote a function like this:
private String getNullAsEmptyString(JsonElement jsonElement) {
return jsonElement.isJsonNull() ? "" : jsonElement.getAsString();
}
So instead of
val geocoder = json.getAsString
You can just use this
val geocoder = getNullAsEmptyString(json);
It returns "" if the element is null and the actual string if it is not
To add to #Henry's answer. In the spirit of Kotlins "OrNull" Adding an extension function:
fun JsonElement.asStringOrNull(): String? {
return if (isJsonNull) null else asString
}
The class JsonElement will throw Unsupported Operation Exception for any getAs<Type> method, because it's an abstract class and makes sense that it is implemented in this way.
For some reason the class JsonObject, does not implement the getAs<Type> methods, so any call to one of these methods will throw an exception.
Calling the toString method on a JsonElement object, may solve your issue in certain circumstances, but isn't probably what you want because it returns the json representation as String (e.g. \"value\") in some cases.
I found out that also a JsonPrimitive class exists and it does implement the getAs<Type> methods. So probably the correct way to proceed is something like this:
String input = "{\"key1\":\"value1\",\"key2\":\"value2\"}";
JsonParser parser = new JsonParser();
JsonElement jsonTree = parser.parse(input);
if(jsonTree != null && jsonTree.isJsonObject()) {
JsonObject jsonObject = jsonTree.getAsJsonObject();
value = jsonObject.get("key1").getAsJsonPrimitive().getAsString()
}
PS. I removed all the nullability mgmt part. If you are coding in Java you probably want to manage this in a better way.
see GitHub source code for JsonElement:
https://github.com/google/gson/blob/master/gson/src/main/java/com/google/gson/JsonElement.java#L178
The code that we already have return us JsonObject. What I want to do is to add a new key and the value for it.
For example, we have an object like this:
{"id":"12","name":"test"}
I want to transform it into this:
{"id":"12","name":"test","status":"complete"}
I didn't find what I need in documentation except using put method. So I wrote this code:
JsonObject object = getJsonObject();
JsonString val = new JsonString() {
public JsonValue.ValueType getValueType() {
return JsonValue.ValueType.STRING;
}
public String getString() {
return "complete";
}
public CharSequence getChars() {
return (CharSequence) "complete";
}
};
object.put("status", val);
But it doesn't work, crashing with :
java.lang.UnsupportedOperationException
I can't understand what is wrong. Have I any other option to complete such a task?
I don't think JsonObject instances are meant to be modified.
I think your best option is to create a new object, copy the existing properties and add the new property to it.
You can use https://docs.oracle.com/javaee/7/api/javax/json/JsonObjectBuilder.html
Not sure if object.put works but you can use the following way to append the details to JSON value:
You can create a different JSON object with the key and value that you want to add to the JSON object and the user object.merge(status, complete, String::concat);
merge() checks for the key:'status' in your JSON object if it does'nt find it then it adds that key:value pair or else it replaces it
.You are not able to compile it because you may not be using jre 1.8.
I've Just verified the following method:
Just create a new JSONObject(org.json.JSONObject not javax.json.JsonObject)
JSONObject modifiedJsonObject= new JSONObject(object.toString());
modifiedJsonObject.put("status", "complete");
I have the following java code in my Android application and wanted a way to convert the Java list to an array that can be used in javascript:
Java:
public void onCompleted(List<GraphUser> users, Response response) {
for(int i = 0; i < users.size(); i++)
{
//add to an array object that can be used in Javascript
webView.loadUrl("javascript:fetchFriends(arrObj)");
}
}
Javascript:
//this is how I want to be able to use the object in Javascript
function parseFriends(usersObjectFromJava){
var users = [];
for (var i = 0; i < usersObjectFromJava.length; i++) {
var u = {
Id: usersObjectFromJava[i].id + "",
UserName: usersObjectFromJava[i].username,
FirstName: usersObjectFromJava[i].first_name,
LastName: usersObjectFromJava[i].last_name,
};
users[i] = u;
}
}
Could some help me with the Java code to create the usersObjectFromJava so that it can be used in javascript?
Use GSON
to convert java objects to JSON string, you can do it by
Gson gson = new Gson();
TestObject o1 = new TestObject("value1", 1);
TestObject o2 = new TestObject("value2", 2);
TestObject o3 = new TestObject("value3", 3);
List<TestObject> list = new ArrayList<TestObject>();
list.add(o1);
list.add(o2);
list.add(o3);
gson.toJson(list) will give you
[{"prop1":"value1","prop2":2},{"prop1":"value2","prop2":2},{"prop1":"value3","prop2":3}]
Now you can use JSON.parse(), to deserialize from JSON to Javascript Object.
I would assume doing this:
Java:
public void onCompleted(List<GraphUser> users, Response response) {
JSONArray arr = new JSONArray();
JSONObject tmp;
try {
for(int i = 0; i < users.size(); i++) {
tmp = new JSONObject();
tmp.put("Id",users.get(i).id); //some public getters inside GraphUser?
tmp.put("Username",users.get(i).username);
tmp.put("FirstName",users.get(i).first_name);
tmp.put("LastName",users.get(i).last_name);
arr.add(tmp);
}
webView.loadUrl("javascript:fetchFriends("+arr.toString()+")");
} catch(JSONException e){
//error handling
}
}
JavaScript:
function fetchFriends(usersObjectFromJava){
var users = usersObjectFromJava;
}
You will have to change the Java-Code a bit (i.e. using public getters or add more/less information to the JSONObjects.
JSON is included in Android by default, so no external libraries are necessary.
I hope i understood your problem.
Small thing i came across: you where using fetchFriends in Java but its called parseFriends in Javascript, I renamed them to fetchFriends
You can use Gson Library.
Gson gson = new GsonBuilder().create();
JsonArray jsonArray = gson.toJsonTree(your_list, TypeClass.class).getAsJsonArray();
http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/Gson.html
Use Jackson.
You'll need to add an " #JsonProperty" annotation to every property of your POJOs you want to pass, then do something like this:
String respStr = "";
for(Object whatever: MyList)
{
JSONObject dato = new JSONObject();
dato.put("FirstField", whatever.SomeData());
dato.put("SecondField", whatever.SomeData2());
StringEntity entity = new StringEntity(dato.toString());
post.setEntity(entity);
webView.loadUrl("javascript:fetchFriends("+entity+")");
}
I am not sure why no answer mentioned about jaxb. I am just thinking jaxb would be a good fit for this type of problems...
For a sample style of annotated jaxb class, please find this.
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class ResponseAsList {
private List < Object > list = new ArrayList < Object > ();
public ResponseAsList() {
// private default constructor for JAXB
}
public List < Object > getList() {
return list;
}
public void setList(List < Object > list) {
this.list = list;
}
}
You will stuff your data in these lists and you will marshal either in xml or a json. After you get a json to the client, you can do a var myArray = JSON.parse(response);...
Although I typically advocate using something like GSON or Jackson to do JSON conversions for you, its pretty easy to roll your own if you're in a limited environment (like Android) and don't want to bundle a bunch of dependencies.
public class JsonHelper {
public static String convertToJSON(List<GraphUser> users) {
StringBuilder sb = new StringBuilder();
for (GraphUser user : users) {
sb.append(convertToJSON(user));
}
return sb.toString();
}
public static String convertToJSON(GraphUser user) {
return new StringBuilder()
.append("{")
.append("\"id\":").append(user.getId()).append(",")
.append("\"admin\":").append(user.isAdmin() ? "true" : "false").append(",")
.append("\"name\":\"").append(user.getName()).append("\",")
.append("\"email\":\"").append(user.getEmail()).append("\"")
.append("}")
.toString();
}
}
You could obviously make a toJSON() method on GraphUser to put the logic if you prefer. Or use an injectable json helper library instead of static methods (I would). Or any number of other abstractions. Many developers prefer to separate representation of model objects into their own object, myself included. Personally, I might model it something like this if I wanted to avoid dependencies:
interface Marshaller<F,T> with methods T marshall(F obj) and F unmarshall(T obj)
interface JsonMarshaller<F> extends Marshaller<String>
class GraphUserMarshaller implements JsonMarshaller<GraphUser>
class GraphUserCollectionMarshaller implements JsonMarshaller<Collection<GraphUser>> which could do type-checking or use the visitor pattern or something to determine the best way to represent this type of collection of objects.
Along the way, I'm sure you'll find some repeated code to extract to super- or composite- classes, particularly once you start modeling collection marshallers this way. Although this can get to be pretty verbose (and tedious), it works particularly well in resource-constrained environments where you want to limit the number of libraries on which you depend.
You can use the Google Gson library (http://code.google.com/p/google-gson/) to convert the Java List Object to JSON. Ensure that the right fields are set like ID, UserName, FirstName, etc and on the java script side that same code would work.
Its just an example, First add javascript interface. It will be a bridge between javascript and java code.
webView.addJavascriptInterface(new JSInterface(), "interface");
In javascript you can add like this,
"window.interface.setPageCount(pageCount1);"
The interface is a keyword in common between java and javascript. create a class JSInterace and define a method setPageCount(int a). The script will return a value, and you can use that value in your java method
I have checked out many pages but most of the tutorials and script return an error code with this type of JSON output. So how would I be able to extract the data from this JSON in Java?:
[
{
"user":{"id":"1","username":"user1"},
"item_name":"item1",
"custom_field":"custom1"
},
{
"user":{"id":"2","username":"user2"},
"item_name":"item2",
"custom_field":"custom2"
},
{
"user":{"id":"3","username":"user3"},
"item_name":"item3",
"custom_field":"custom3"
}
]
If you want to use Gson, then first you declare classes for holding each element and sub elements:
public class MyUser {
public String id;
public String username;
}
public class MyElement {
public MyUser user;
public String item_name;
public String custom_field;
}
Then you declare an array of the outermost element (because in your case the JSON object is a JSON array), and assign it:
MyElement[] data = gson.fromJson (myJSONString, MyElement[].class);
Then you simply access the elements of data.
The important thing to remember is that the names and types of the attributes you declare should match the ones in the JSON string. e.g. "id", "item_name" etc.
If your trying to serialize/deserialize json in Java I would recommend using Jackson. http://jackson.codehaus.org/
Once you have Jackson downloaded you can deserialize the json strings to an object which matches the objects in JSON.
Jackson provides annotations that can be attached to your class which make deserialization pretty simple.
You could try JSON Simple
http://code.google.com/p/json-simple/
Example:
JSONParser jsonParser = new JSONParser();
JSONArray jsonArray = (JSONArray) jsonParser.parse(jsonDataString);
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject obj = (JSONObject) jsonArray.get(i);
//Access data with obj.get("item_name")
}
Just be careful to check for nulls/be careful with casting and such.