Android: How to add existing JSONObject to existing key - java

I have a data structure like this:
source: {
property_1: String,
property_2: String,
property_3: {
property_31: String
}
}
I want to have a function like this:
private JSONObject mergeProperty(JSONObject source, String propertyName, JSONObject newData)
in which, source is data above, propertyName = "property_3", and
newData: {
property_32: String,
property_33: int
}
with result of calling mergeProperty(source, "property_3", newData) as:
output: {
property_1: String,
property_2: String,
property_3: {
property_31: String,
property_32: String,
property_33: int
}
}
Is there any simple method to achieve this without having to map the JSON object to HashMap first? I found no built-in JSONObject function which corelates to my problem.

If I got your intention right, this code must do the job. Please, note, that this will mutate original source, so you might need to pass a copy, if mutating original one is not what you want. Also, here I assume that propertyName is on the first level of your source JSON, and is JSON, too, else this will throw a JSONException.
JSONObject mergeTarget = source.getJSONObject(propertyName);
Iterator<String> keys = newData.keys();
while (keys.hasNext()) {
String key = keys.next();
mergeTarget.put(key, newData.get(key));
}

Try accumulate method of org.json.JSONObject.
Below code may be useful to you.
public class Test {
public static void main(String[] args){
System.out.println("test");
JSONObject source = new JSONObject("{\"property_1\":\"String\",\"property_2\":\"String\",\"property_3\":{\"property_31\":\"String\"}}");
JSONObject newData = new JSONObject("{\"property_32\":\"String\",\"property_33\":\"int\"}");
System.out.println("Before merge :"+source.toString());
mergeProperty(source, "property_3", newData);
System.out.println("After merge :"+source.toString());
}
private static void mergeProperty(JSONObject source, String property, JSONObject newData){
for (Object key : newData.keySet()){
String keyStr = (String)key;
Object keyvalue = newData.get(keyStr);
source.getJSONObject(property).accumulate(keyStr , keyvalue);
}
}
}

Related

How to iterate over JSONObject and found id by value which already known, for example I want to get id of value "ТС-41" how can I do it?

{
"0":"",
"54049":"ОП.мз-61а",
"100606":"КМ-41",
"100609":"МТ-41",
"100612":"ЕМ-41",
"100684":"ХК-51",
"100685":"ЕМ-51",
"100687":"КМ-51",
"100688":"МТ-51",
"100718":"ХК-51/1",
"100719":"ХК-51/2",
"100748":"ТС-61",
"100749":"ТС-61/1",
"100750":"ТС-61/2",
"100754":"ЕМ-61",
"100758":"ІМ-61/1МБ",
"100759":"ІМ-61/2ГТ",
"100760":"МБ-61",
"100767":"ТС-51",
"100770":"ТС-41",
"100777":"ТС.м-61",
"100778":"МТ.м-61",
"100779":"ЕМ.м-61",
"100780":"ТМ.м-61",
"100781":"ТМ.м-62",
"100782":"ГМ.м-61",
"100783":"ВІ.м-61",
"100786":"ХМ.м-61"
}
You'll need to iterate over the JSONObject keys and compare the value until a match.
final String knownValue = "TC-41";
final Iterator<String> iterable = jsonObject.keys();
while (iterable.hasNext()) {
String key = iterable.next();
if (jsonObject.getString(key).equals(knownValue)) {
// key has the value you are looking for
return;
}
}
Use JSON Classes for parsing
JSONObject mainObject = new JSONObject(Your_Sring_data);
String id = mainObject .getString("100770");
//here in this **id** string you can get value for **"TC-41"**

How do we retrieve all keys along with their prefixes from a JSON document

{
"empId":"1",
"name":"Alex",
"role":"president",
"phone":"123",
"address": {
"street":"xyz",
"city":"hyd",
"pincode":400123
}
}
I want to retrieve keys as following so that I can allow the user to choose such keys in the UI.
keys: ["empId","name","role","phone", "address", "address.street", "address.city",
"address.pincode"]
The same can be used for querying on Mongo directly. I tried using JSONObject and get keys but I am unable to fetch documents along with the path they come from.
Please let me know if there's a direct way I can use in Java or if Mongo has a way to get all keys from where they are coming
You can do that using recursion.
Here is an example:
public static void main(String[] args) throws ParseException {
String str = "{ \"empId\":\"1\", \"name\":\"Alex\", \"role\":\"president\", \"phone\":\"123\", \"address\": { \"street\":\"xyz\", \"city\":\"hyd\", \"pincode\":400123 }}";
JSONObject obj = (JSONObject) new JSONParser().parse(str);
List<String> keysList = new ArrayList<>();
recLevels(keysList, obj, "");
System.out.println(keysList);
}
public static void recLevels(List<String> keysList, JSONObject obj, String prefix) {
Set<String> keys = (Set<String>) obj.keySet();
for (String key : keys) {
keysList.add(prefix + (prefix.isEmpty() ? "" : ".") + key);
if (obj.get(key) instanceof JSONObject) {
recLevels(keysList, (JSONObject) obj.get(key), prefix + (prefix.isEmpty() ? "" : ".") + key);
}
}
}
What the recLevels method does is to go through all the keys of an object and check is any of these keys has an object as its value if (obj.get(key) instanceof JSONObject), if it does recLevels is called again for that object and the process is repeated for that object (one level down).
The important part here is the prefix variable which is used to store the previous keys on the previous levels.
You can create additional array and push all keys in that array.
Use JSON.Stringyfy function to present it as string to end user.
var keys = [],
sourceArray = [{
"empId":"1",
"name":"Alex",
"role":"president",
"phone":"123",
"address": {
"street":"xyz",
"city":"hyd",
"pincode":400123
}
}]; //Test data
$.each(sourceArray, function(k, v) {
//k is the key and v is the value (key-value pair)
keys.push(k);
});
//You have all the keys - use at your disposal
Note: I've not tested this code in absence of source-code, please validate and modify as per your actual code.

How to convert any Object to String?

Here is my code:
for (String toEmail : toEmailList)
{
Log.i("GMail","toEmail: "+toEmail);
emailMessage.addRecipient(Message.RecipientType.TO, new InternetAddress(toEmail));
}
Please give me some suggestion about this.
To convert any object to string there are several methods in Java
String convertedToString = String.valueOf(Object); //method 1
String convertedToString = "" + Object; //method 2
String convertedToString = Object.toString(); //method 3
I would prefer the first and third
EDIT
If working in kotlin, the official android language
val number: Int = 12345
String convertAndAppendToString = "number = $number" //method 1
String convertObjectMemberToString = "number = ${Object.number}" //method 2
String convertedToString = Object.toString() //method 3
If the class does not have toString() method, then you can use ToStringBuilder class from org.apache.commons:commons-lang3
pom.xml:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12</version>
</dependency>
code:
ToStringBuilder.reflectionToString(yourObject)
"toString()" is Very useful method which returns a string representation of an object. The "toString()" method returns a string reperentation an object.It is recommended that all subclasses override this method.
Declaration: java.lang.Object.toString()
Since, you have not mentioned which object you want to convert, so I am just using any object in sample code.
Integer integerObject = 5;
String convertedStringObject = integerObject .toString();
System.out.println(convertedStringObject );
You can find the complete code here.
You can test the code here.
I've written a few methods for convert by Gson library and java 1.8 .
thay are daynamic model for convert.
string to object
object to string
List to string
string to List
HashMap to String
String to JsonObj
//saeedmpt
public static String convertMapToString(Map<String, String> data) {
//convert Map to String
return new GsonBuilder().setPrettyPrinting().create().toJson(data);
}
public static <T> List<T> convertStringToList(String strListObj) {
//convert string json to object List
return new Gson().fromJson(strListObj, new TypeToken<List<Object>>() {
}.getType());
}
public static <T> T convertStringToObj(String strObj, Class<T> classOfT) {
//convert string json to object
return new Gson().fromJson(strObj, (Type) classOfT);
}
public static JsonObject convertStringToJsonObj(String strObj) {
//convert string json to object
return new Gson().fromJson(strObj, JsonObject.class);
}
public static <T> String convertListObjToString(List<T> listObj) {
//convert object list to string json for
return new Gson().toJson(listObj, new TypeToken<List<T>>() {
}.getType());
}
public static String convertObjToString(Object clsObj) {
//convert object to string json
String jsonSender = new Gson().toJson(clsObj, new TypeToken<Object>() {
}.getType());
return jsonSender;
}
I am try to convert Object type variable into string using this line of code
try this to convert object value to string:
Java Code
Object dataobject=value;
//convert object into String
String convert= String.valueOf(dataobject);
I am not getting your question properly but as per your heading, you can convert any type of object to string by using toString() function on a String Object.
try this one
ObjectMapper mapper = new ObjectMapper();
String oldSerial = mapper.writeValueAsString(list);

json.org Java: JSON array parsing bug [duplicate]

This question already has answers here:
How to parse JSON in Java
(36 answers)
Closed 4 years ago.
I have JSON object as follows:
member = "{interests : [{interestKey:Dogs}, {interestKey:Cats}]}";
In Java I want to parse the above json object and store the values in an arraylist.
I am seeking some code through which I can achieve this.
I'm assuming you want to store the interestKeys in a list.
Using the org.json library:
JSONObject obj = new JSONObject("{interests : [{interestKey:Dogs}, {interestKey:Cats}]}");
List<String> list = new ArrayList<String>();
JSONArray array = obj.getJSONArray("interests");
for(int i = 0 ; i < array.length() ; i++){
list.add(array.getJSONObject(i).getString("interestKey"));
}
public class JsonParsing {
public static Properties properties = null;
public static JSONObject jsonObject = null;
static {
properties = new Properties();
}
public static void main(String[] args) {
try {
JSONParser jsonParser = new JSONParser();
File file = new File("src/main/java/read.json");
Object object = jsonParser.parse(new FileReader(file));
jsonObject = (JSONObject) object;
parseJson(jsonObject);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void getArray(Object object2) throws ParseException {
JSONArray jsonArr = (JSONArray) object2;
for (int k = 0; k < jsonArr.size(); k++) {
if (jsonArr.get(k) instanceof JSONObject) {
parseJson((JSONObject) jsonArr.get(k));
} else {
System.out.println(jsonArr.get(k));
}
}
}
public static void parseJson(JSONObject jsonObject) throws ParseException {
Set<Object> set = jsonObject.keySet();
Iterator<Object> iterator = set.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
if (jsonObject.get(obj) instanceof JSONArray) {
System.out.println(obj.toString());
getArray(jsonObject.get(obj));
} else {
if (jsonObject.get(obj) instanceof JSONObject) {
parseJson((JSONObject) jsonObject.get(obj));
} else {
System.out.println(obj.toString() + "\t"
+ jsonObject.get(obj));
}
}
}
}}
Thank you so much to #Code in another answer. I can read any JSON file thanks to your code. Now, I'm trying to organize all the elements by levels, for could use them!
I was working with Android reading a JSON from an URL and the only I had to change was the lines
Set<Object> set = jsonObject.keySet();
Iterator<Object> iterator = set.iterator();
for
Iterator<?> iterator = jsonObject.keys();
I share my implementation, to help someone:
public void parseJson(JSONObject jsonObject) throws ParseException, JSONException {
Iterator<?> iterator = jsonObject.keys();
while (iterator.hasNext()) {
String obj = iterator.next().toString();
if (jsonObject.get(obj) instanceof JSONArray) {
//Toast.makeText(MainActivity.this, "Objeto: JSONArray", Toast.LENGTH_SHORT).show();
//System.out.println(obj.toString());
TextView txtView = new TextView(this);
txtView.setText(obj.toString());
layoutIzq.addView(txtView);
getArray(jsonObject.get(obj));
} else {
if (jsonObject.get(obj) instanceof JSONObject) {
//Toast.makeText(MainActivity.this, "Objeto: JSONObject", Toast.LENGTH_SHORT).show();
parseJson((JSONObject) jsonObject.get(obj));
} else {
//Toast.makeText(MainActivity.this, "Objeto: Value", Toast.LENGTH_SHORT).show();
//System.out.println(obj.toString() + "\t"+ jsonObject.get(obj));
TextView txtView = new TextView(this);
txtView.setText(obj.toString() + "\t"+ jsonObject.get(obj));
layoutIzq.addView(txtView);
}
}
}
}
1.) Create an arraylist of appropriate type, in this case i.e String
2.) Create a JSONObject while passing your string to JSONObject constructor as input
As JSONObject notation is represented by braces i.e {}
Where as JSONArray notation is represented by square brackets i.e []
3.) Retrieve JSONArray from JSONObject (created at 2nd step) using "interests" as index.
4.) Traverse JASONArray using loops upto the length of array provided by length() function
5.) Retrieve your JSONObjects from JSONArray using getJSONObject(index) function
6.) Fetch the data from JSONObject using index '"interestKey"'.
Note : JSON parsing uses the escape sequence for special nested characters if the json response (usually from other JSON response APIs) contains quotes (") like this
`"{"key":"value"}"`
should be like this
`"{\"key\":\"value\"}"`
so you can use JSONParser to achieve escaped sequence format for safety as
JSONParser parser = new JSONParser();
JSONObject json = (JSONObject) parser.parse(inputString);
Code :
JSONParser parser = new JSONParser();
String response = "{interests : [{interestKey:Dogs}, {interestKey:Cats}]}";
JSONObject jsonObj = (JSONObject) parser.parse(response);
or
JSONObject jsonObj = new JSONObject("{interests : [{interestKey:Dogs}, {interestKey:Cats}]}");
List<String> interestList = new ArrayList<String>();
JSONArray jsonArray = jsonObj.getJSONArray("interests");
for(int i = 0 ; i < jsonArray.length() ; i++){
interestList.add(jsonArray.getJSONObject(i).optString("interestKey"));
}
Note : Sometime you may see some exceptions when the values are not available in appropriate type or is there is no mapping key so in those cases when you are not sure about the presence of value so use optString, optInt, optBoolean etc which will simply return the default value if it is not present and even try to convert value to int if it is of string type and vice-versa so Simply No null or NumberFormat exceptions at all in case of missing key or value
From docs
Get an optional string associated with a key. It returns the
defaultValue if there is no such key.
public String optString(String key, String defaultValue) {
String missingKeyValue = json_data.optString("status","N/A");
// note there is no such key as "status" in response
// will return "N/A" if no key found
or To get empty string i.e "" if no key found then simply use
String missingKeyValue = json_data.optString("status");
// will return "" if no key found where "" is an empty string
Further reference to study
How to convert String to JSONObject in Java
Convert one array list item into multiple Items
There are many JSON libraries available in Java.
The most notorious ones are: Jackson, GSON, Genson, FastJson and org.json.
There are typically three things one should look at for choosing any library:
Performance
Ease of use (code is simple to write and legible) - that goes with features.
For mobile apps: dependency/jar size
Specifically for JSON libraries (and any serialization/deserialization libs), databinding is also usually of interest as it removes the need of writing boiler-plate code to pack/unpack the data.
For 1, see this benchmark: https://github.com/fabienrenaud/java-json-benchmark I did using JMH which compares (jackson, gson, genson, fastjson, org.json, jsonp) performance of serializers and deserializers using stream and databind APIs.
For 2, you can find numerous examples on the Internet. The benchmark above can also be used as a source of examples...
Quick takeaway of the benchmark: Jackson performs 5 to 6 times better than org.json and more than twice better than GSON.
For your particular example, the following code decodes your json with jackson:
public class MyObj {
private List<Interest> interests;
static final class Interest {
private String interestKey;
}
private static final ObjectMapper MAPPER = new ObjectMapper();
public static void main(String[] args) throws IOException {
MyObj o = JACKSON.readValue("{\"interests\": [{\"interestKey\": \"Dogs\"}, {\"interestKey\": \"Cats\" }]}", MyObj.class);
}
}
Let me know if you have any questions.

How to maintain the order of a JSONObject

I am using a JSONObject in order to remove a certin attribute I don't need in a JSON String:
JSONObject jsonObject = new JSONObject(jsonString);
jsonObject.remove("owner");
jsonString = jsonObject.toString();
It works ok however the problem is that the JSONObject is "an unordered collection of name/value pairs" and I want to maintain the original order the String had before it went through the JSONObject manipulation.
Any idea how to do this?
try this
JSONObject jsonObject = new JSONObject(jsonString) {
/**
* changes the value of JSONObject.map to a LinkedHashMap in order to maintain
* order of keys.
*/
#Override
public JSONObject put(String key, Object value) throws JSONException {
try {
Field map = JSONObject.class.getDeclaredField("map");
map.setAccessible(true);
Object mapValue = map.get(this);
if (!(mapValue instanceof LinkedHashMap)) {
map.set(this, new LinkedHashMap<>());
}
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
return super.put(key, value);
}
};
jsonObject.remove("owner");
jsonString=jsonObject.toString();
You can't.
That is why we call it an unordered collection of name/value pairs.
Why you would need to do this, I'm not sure. But if you want ordering, you'll have to use a json array.
I have faced the same problem recently and just transitioned all our tests (which expect JSON attributes to be in the same order) to another JSON library:
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.3.5</version>
</dependency>
Internally it uses a LinkedHashMap, which maintains the order of attributes. This library is functionally equivalent to the json.org library, so I don't see any reason why not use it instead, at least for tests.
You can go for the JsonObject provided by the com.google.gson it is nearly the same with the JSONObject by org.json but some different functions.
For converting String to Json object and also maintains the order you can use:
Gson gson = new Gson();
JsonObject jsonObject = gson.fromJson(<Json String>, JsonObject.class);
For eg:-
String jsonString = "your json String";
JsonObject jsonObject = gson.fromJson(jsonString, JsonObject.class);
It just maintains the order of the JsonObject from the String.
If you can edit the server repose then change it to array of JSON objects.
JSON:
[
{PropertyName:"Date of Issue:",PropertyValue:"3/21/2011"},
PropertyName:"Report No:",PropertyValue:"2131196186"},{PropertyName:"Weight:",PropertyValue:"1.00"},
{PropertyName:"Report Type:",PropertyValue:"DG"}
]
And I handled it with JSONArray in client side (Android):
String tempresult="[{PropertyName:"Date of Issue:",PropertyValue:"3/21/2011"},PropertyName:"Report No:",PropertyValue:"2131196186"},PropertyName:"Weight:",PropertyValue:"1.00"},{PropertyName:"Report Type:",PropertyValue:"DG"}]"
JSONArray array = new JSONArray(tempresult);
for (int i = 0; i < array.length(); i++)
{
String key = array.getJSONObject(i).getString("PropertyName");
String value = array.getJSONObject(i).getString("PropertyValue");
rtnObject.put(key.trim(),value.trim()); //rtnObject is LinkedHashMap but can be any other object which can keep order.
}
You can use Jsckson library in case to maintain the order of Json keys.
It internally uses LinkedHashMap ( ordered ).
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
The code to remove a field, the removed JsonToken could itself be read if required.
String jsonString = "{\"name\":\"abc\",\"address\":\"add\",\"data\":[\"some 1\",\"some 2\",\"some3 3\"],\"age\":12,\"position\":8810.21}";
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(jsonString);
System.out.println("In original order:"+node.toString());
JsonToken removedToken = ((ObjectNode) node).remove("address").asToken();
System.out.println("Aft removal order:"+node.toString());
ObjectNode implementation uses a LinkedHashMap, which maintains the insertion order:
public ObjectNode(JsonNodeFactory nc) {
super(nc);
_children = new LinkedHashMap<String, JsonNode>();
}
Go on JSONObject class
Change from HashMap() to LinkedHashMap()
/**
* Construct an empty JSONObject.
*/
public JSONObject() {
this.map = new LinkedHashMap();
}
The LinkedHashMap class extends the Hashmap class. This class uses a doubly linked list containing all the entries of the hashed table, in the order in which the keys were inserted in the table: this allows the keys to be "ordered".
This is not easy, the main idea is to use LinkedHashMap, either pass in to the constructor (JSONObject(Map map)), or modify bytecode to handle the String parameter (JSONObject(String source)), which is the main use case. I got a solution in oson:
public static JSONObject getJSONObject(String source) {
try {
int lineNumberToReplace = 157;
ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.get("org.json.JSONObject");
if (ctClass.isFrozen() || ctClass.isModified()) {
if (source == null) {
return new JSONObject();
} else {
return new JSONObject(source);
}
}
ctClass.stopPruning(true);
CtConstructor declaredConstructor = ctClass.getDeclaredConstructor(new CtClass[] {});
CodeAttribute codeAttribute = declaredConstructor.getMethodInfo().getCodeAttribute();
LineNumberAttribute lineNumberAttribute = (LineNumberAttribute)codeAttribute.getAttribute(LineNumberAttribute.tag);
// Index in bytecode array where the instruction starts
int startPc = lineNumberAttribute.toStartPc(lineNumberToReplace);
// Index in the bytecode array where the following instruction starts
int endPc = lineNumberAttribute.toStartPc(lineNumberToReplace+1);
// Let's now get the bytecode array
byte[] code = codeAttribute.getCode();
for (int i = startPc; i < endPc; i++) {
// change byte to a no operation code
code[i] = CodeAttribute.NOP;
}
declaredConstructor.insertAt(lineNumberToReplace, true, "$0.map = new java.util.LinkedHashMap();");
ctClass.writeFile();
if (source == null) {
return (JSONObject) ctClass.toClass().getConstructor().newInstance();
} else {
return (JSONObject) ctClass.toClass().getConstructor(String.class).newInstance(source);
}
} catch (Exception e) {
//e.printStackTrace();
}
if (source == null) {
return new JSONObject();
} else {
return new JSONObject(source);
}
}
need to include jar file from using mvn
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.1.GA</version>
</dependency>
From Android 20, JSONObject preserves the order as it uses LinkedHashMap to store namevaluepairs. Android 19 and below uses HashMap to store namevaluepairs. So, Android 19 and below doesn't preserve the order. If you are using 20 or above, don't worry, JSONObject will preserve the order. Or else, use JSONArray instead.
In JDK 8 and above, We can do it by using nashorn engine, supported in JDK 8.
Java 8 support to use js engine to evaluate:
String content = ..json content...
String name = "test";
String result = (String) engine.eval("var json = JSON.stringify("+content+");"
+ "var jsResult = JSON.parse(json);"
+ "jsResult.name = \"" + name + "\";"
+ "jsResult.version = \"1.0\";"
+ "JSON.stringify( jsResult );"
);
I was able to do this with help of classpath overriding.
created package package org.json.simple which is same as in jar and class named as JSONObject.
Took existing code from jar and updated the class by extending LinkedHashmap instead of Hashmap
by doing these 2 steps it will maintain the order, because preference of picking `JSONObject will be higher to pick from the new package created in step 1 than the jar.
I accomplished it by doing a:
JSONObject(json).put(key, ObjectMapper().writeValueAsString(ObjectMapper().readValue(string, whatever::class)))
So essentially I deserialize a string to an ordered class, then I serialize it again. But then I also had to format that string afterwards to remove escapes.
.replace("\\\"", "\"").replace("\"{", "{").replace("}\"", "}")
You may also have to replace null items as well if you don't want nulls.

Categories

Resources