I have JSON with objects in specific order:
{
"Aaa": {
"Langs": {
"Val": [
"Test"
],
"Pro": [
"Test2"
]
}
},
"Bbb": {
"Langs": {
"Val": [
"Test"
],
"Pro": [
"Test2"
]
}
},
"Ddd": {
"Langs": {
"Val": [
"Test"
],
"Pro": [
]
}
},
}
And I would like to add new object Ccc between Bbb and Ddd. I tried to configure object mapper like this:
ObjectMapper mapper = new ObjectMapper()
.enable(SerializationFeature.INDENT_OUTPUT)
.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
and then print with this code, but Ccc ends at the end of file.
DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter();
prettyPrinter.indentArraysWith(DefaultIndenter.SYSTEM_LINEFEED_INSTANCE);
//Write whole JSON in FILE
String finalJson = mapper.writer(prettyPrinter).writeValueAsString(rootFlores);
finalJson = finalJson.replaceAll("\\[ ]", "[" + System.lineSeparator() + " ]");
finalJson = finalJson.replaceAll("/", "\\\\/");
Files.write(Paths.get("DictionaryFlores_new.json"), Collections.singleton(finalJson));
Is here a way how to print JSON ordered?
Jackson deserialization/serialization does not sort properties
According to this answer, the Jackson SORT_PROPERTIES_ALPHABETICALLY only applies to POJO properties, not Maps. In JSON there is no difference between a Map and an Object, so you need to set the order in the Map first by using a LinkedHashMap or TreeMap
By definition, the keys of an object are unordered. I guess some libraries could offer an option to control the order of the keys when stringifying, but I wouldn't count on it.
When you need a certain order in json, you need to use an array. Of course, then you'd have to move the keys to a property in the child objects, and then the resulting array could only be indexed by number (not by the key). So then you might have to do additional processing to covert the data structure in the JSON to the data structure you really want to process.
Since you seems ready to use regex to update a JSON, I would suggest a "safer" approach. Don't try to create a pattern that would unsure that you don't update a value somewhere.
Iterate you values, on object at the time. Stringify the object and append the String yourself. That way, you are in charge of the object order. Example :
StringBuilder sb = new StringBuilder("{");
List<JsonPOJO> list = new ArrayList<>();
//populate the list
for(JsonPOJO pojo : list){
sb.append(pojo.stringify()).append(",");
}
sb.setLength(sb.length() - 1); //remove the last commma
sb.append("}");
Here, you are only managing the comma between each JSON object, not create the "complex" part about the JSON. And you are in full control of the order of the value in the String representation, it will only depend on the way you populate the List.
Note: sorry for the "draft" code, I don't really have access to my system here so just write this snippet to give you a basic idea on how to "manage" a JSON without having to recreating an API completely.
Note2: I would note suggest this unless this looks really necessary. As you mention in a comment, you are have only the problem with one key where you already have a JSON with 80000 keys, so I guess this is a "bad luck" scenario asking for last resort solution ;)
I am using the following libraries to create some JSON object.
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
The json I am trying to create is this:
{
"function": "create_contact_group",
"parameters": [{
"user_id": "teer",
"comp_id": "97",
"contact_group_name": "Test01",
"invite_user_list": [{
"invite_user_id": "steve"
}]
}]
}
My function looks like this:
public JSONObject createJSONRequest() {
/* Create json object */
JSONObject jsonObject = new JSONObject();
Map<String, String> map = new HashMap<>();
map.put("user_id", "teer");
map.put("comp_id", "97");
map.put("contact_group_name", "Test01");
List<String> mInviteUserList = new ArrayList<>();
mInviteUserList.add("steve");
/* Create the list of invitee */
Map<String, String> inviteList = new HashMap<>();
for(String user : mInviteUserList) {
inviteList.put("invite_user_id", user);
}
/* Add the invitees into the json array */
JSONArray inviteArray = new JSONArray();
inviteArray.add(inviteList);
/* Add the json array to the json object */
jsonObject.put("invite_user_list", inviteArray);
JSONArray parameterlist = new JSONArray();
parameterlist.add(map);
parameterlist.add(jsonObject);
jsonObject.put("parameters", parameterlist);
jsonObject.put("function", "create_contact_group");
Log.d(TAG, "jsonObject: " + jsonObject.toJSONString());
return jsonObject;
}
However, the function crashes when I get to the following line:
Log.d(TAG, "jsonObject: " + jsonObject.toJSONString())
I think it has something to do with this line here:
parameterlist.add(jsonObject);
Stacktrace:
java.lang.StackOverflowError java.lang.AbstractStringBuilder.enlargeBuffer(AbstractStringBuilder.java:95) at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:132)
at java.lang.StringBuffer.append(StringBuffer.java:126) at org.json.simple.JSONValue.escape(JSONValue.java:266) at org.json.simple.JSONObject.toJSONString(JSONObject.java:116)
Many thanks for any suggestions,
There are a couple of issues in your code.
One issue is that the structure you create in the java code will not match the structure that you show above. This I will try to describe a bit below.
The second issue is that you get a stackoverflow exception (which you know but don't know why).
The stackoverflow exception is thrown cause the program runs out of the stack memory assigned by the computer. Why you ask? Well, cause you create a recursive or cyclic JSON object.
This isn't good, but its not that big a deal cause its kinda easy to fix.
So why does the program throw this exception? Well, look at the following snippet:
JSONArray parameterlist = new JSONArray();
parameterlist.add(map);
parameterlist.add(jsonObject);
jsonObject.put("parameters", parameterlist);
jsonObject.put("function", "create_contact_group");
You create a JSONArray and then add the JSONObject created before to the array.
After that you add the same array to the object that is already in the array.
I expect that you see the issue with that!
So, that should not be done.
And how to fix this? Well, I kinda think its better that I describe how you should write the code to get the structure you are actually asking for, so I'll try do that...
What to do...?
A JSON (JavaScript Object Notation) -object is always declared with this type of brackets: {} a JSON array with [], so, the JSON you are trying to generate should be in the following data types:
{ // <= Root object (a JSON-object).
"function": "create_contact_group", // <= Key in the root-object (where the key is a string and the value a string)
"parameters": [ // <= Key in the root-object (where the key is a string and the value is an array.
{ // <= Object inside the array.
"user_id": "teer", // Key (string/string)
"comp_id": "97", // Key (string/string)
"contact_group_name": "Test01", // Key (string/string)
"invite_user_list": [ // Key (string/array)
{ // Object inside the invite_user_list array
"invite_user_id": "steve" // Key (string/string)
}
]
}
]
}
So when creating the JSON-object in java, you will want to create a root object then add all the diff params inside it.
Adding a value to a JSONObject is done with the JSONObject.put(string, Object) method, where the string is a key and the object a value.
So to start, I would recommend creating the parameters list.
In your case, you use a HashMap for the objects, which is not really wrong, but not really necessary either, I would just stick to a JSONObject, which is not all that different than a HashMap<string, Object>.
So instead of map.put(...), you could do something like:
JSONObject param = new JSONObject();
param.put("user_id", "teer");
param.put("comp_id", "97");
param.put("contact_group_name", "Test01");
Now, one of the objects values should be an array (invite_user_id) and the easiest way to add an array to the object is to create a JSONArray and then just add it.
JSONArray inviteList = new JSONArray();
// Then you need to add an object to the array for each `user` that has invited.
// For-loop here maybe?
JSONObject invitee = new JSONObject();
invitee.put("invite_user_id", user);
inviteList,add(invitee); // This will make it into an array with objects, I.E., [ { "invite_user_id": "Steve" } ]
After creating the invite list, add it to the param object like:
param.put("invite_user_list", inviteList);
// Now, param should be in its own list too, so you should probably create a JSONArray for the params.
// Ill leave that to you, and we pretend we have a list of the param objects named "params".
And then at the end, you create the root object and set its values:
JSONObject root = new JSONObject();
root.put("parameters", params);
root.put("function", "create_contact_group");
And that should be it.
This should create a JSON-string with the structure that you made above. But I would recommend testing (and writing unit tests!) for this (especially as I have written this code in the browser!).
But why?!
I guess I should try to describe why your code was not working as the one I described above.
You start by creating a root object, so far so good (can create it at start or at the time you need it, doesn't really matter), after that you create a HashMap and add the properties to it.
So far this is also legit (you could later create a JSONObject from the map).
In the next part, you create an ArrayList (im not really sure why) and add a name to it, and then another HashMap which you add the single name to (key invite_user_list) inside a for-loop.
This is either not necessary (cause its just one name) or wrong (if there is supposed to be more names in a real life execution of the code), in case of unnecessary, the for-loop shouldn't be there and in case of "not like real life" it should not be added to a Map!
Instead the invieList should have been an array, and each entry added should have been a object which had the "invite_user_id" key set to the name.
After that, you add the inviteList HashMap to a newly created JSONArray, I guess this could be kinda okay, if you only want one object ever in the array, else I would recommend creating it before the loop and add each entry into it!
The inviteArray is then put inside the root object with the key invite_user_list, after that you create another JSONArray and add both the map (your parameters created at the start) and the JSONObject (root) created first of all.
But the thing you do after that, is why you are getting a stackoverflow exception, you add the parameterlist (which contains the jsonObject (root)) to the jsonObject, which makes the jsonObject exist inside an array that is inside itself!
This creates a cyclic JSON structure which will never end if the whole thing was to be unrolled, hence the computer throws the exception.
The structure of the resulting object would also be wrong, cause it would look something like this:
{ // Root (jsonObject)
"invite_user_list": [
{ "invite_user_id": "steve" }
]
"parameters": [
{ // The "map" hashmap
"user_id", "teer",
"comp_id": "97",
"contact_group_name": "Test01"
},
{ // The jsonObject object (which is also the root!)
"invite_user_list": [
{ "invite_user_id": "steve" }
],
"parameters": [
{ // The "map" hashmap
"user_id", "teer",
"comp_id": "97",
"contact_group_name": "Test01"
},
{
// The jsonObject object again (which is also the root and the parent!)
// ... and so on til eternity!
}
],
"function": "create_contact_group"
}
],
"function": "create_contact_group"
}
Extra...
I would like to add here at the end (where I hope you end up after reading the whole wall of text that I wrote above, cause you might have learnt something!) that there is a easier way of doing it.
Now, I haven't used this lib myself, but from what I understand, it should be able to serialize a whole object, the lib can be found at Googles github repos which can be used as a json serializer and convert a class-instance to a json string, then you could just create a class for the whole object and fill it up and serialize it at the end of the function, without using either JSONArray nor JSONObject.
The issue is due to recursion process that occurs when you are trying to add the JsonObject to JsonArray and viceVersa.
The thing you are doing is,
JSONArray parameterlist = new JSONArray();
parameterlist.add(map);
parameterlist.add(jsonObject);
And then
jsonObject.put("parameters", parameterlist);
The problem is when you print the object using jsonObject.toJSONString(), Then at first it will fetch the parameterlist then as jsonObject is part of the keyvalue pair on the parameterlist JsonArray it will refetch the jsonObject which then again fetch the parameterlist and this process continues on and hence causing the StackOverflow Issue.
The Quick Solution is to create new JsonObject while assigning the parameterList,
JSONArray parameterlist = new JSONArray();
parameterlist.add(map);
parameterlist.add(jsonObject);
JSONObject newJson = new JSONObject();
newJson.put("parameters", parameterlist);
System.out.println(newJson.toJSONString());
I'm trying to get one JSON object and iterate it. In this case it should iterate only once because I'm having only one complete JSON object, if it has multiple, it should iterate multiple times. But rather it shows the system.out.println string twice. I don't understand whats wrong in this code?
String str = "{\"userId\":\"1234\",\"businessPrimaryInfo\":{\"53bd2a4\":{\"businessSpecificInfo\":{\"businessType\":\"Manufacturing\",\"tradingPlace\":\"Hyderabad\"}},\"53bd2a4e\":{\"businessSpecificInfo\":{\"businessType\":\"Milling\",\"tradingPlace\":\"Mumbai\"}}}}";
JSONObject jsonObj = new JSONObject(str);
Iterator<String> keys = jsonObj.keys();
// Iterate all the users.
while (keys.hasNext()) {
String key = keys.next();
try {
// If the user has Business primary info as JSON object.
if (jsonObj.has("businessPrimaryInfo")) {
JSONObject jsonBizPrimaryInfo = jsonObj
.getJSONObject("businessPrimaryInfo");
System.out.println("Object is:" + jsonBizPrimaryInfo);
}
} finally {
}
}
Please have a look and let me know where I'm doing wrong.
The two keys that are causing your loop to iterate twice are: userId and businessPrimaryInfo. But you ask the main JSON object if it has a businessPrimaryInfo key. Which it has for every iteration.
What you need to do is check that the current key is businessPrimaryInfo.
Or, you can just ask the primary object if it has a businessPrimaryInfo key, and if so, ask for that child object.
I am trying to create a structure where there will be a list of multiple String values e.g. "0212" and I want to have three ArrayLists. The first ArrayList will take the first part of the value "02", the second will take the second part "1" and the third will take the third value "2". I then want to be able to iterate through the list of values so that I can find the specific one quicker as multiple values will have the same value for the first and second part of the value. I then want to link that to an object that has a value matching "0212". I hope that someone understands what I am trying to explain and if anyone can help me, I would much appreciate it. Thank you in advance.
This is the code that I have at the moment which matches the string value against the DataObject address value in the ArrayList:
public void setUpValues()
{
String otherString = "4210";
Iterator<DataObject> it = dataObjects.iterator();
while(it.hasNext())
{
DataObject currentDataObject = it.next();
if(currentDataObject.getAddress().equals(otherString))
{
System.out.println("IT WORKSSSSSS!");
currentDataObject.setValue("AHHHHHHHHH");
System.out.println("Data Object Address: " + currentDataObject.getAddress());
System.out.println("Data Object Type: " + currentDataObject.getType());
System.out.println("Data Object Value: " + currentDataObject.getValue());
System.out.println("Data Object Range: " + currentDataObject.getRange());
}
else
{
}
}
}
Since the values are so tightly defined (three sections, each represented by one byte), I think you can build a lightweight solution based on Map:
Map<Byte, ArrayList<Byte>> firstSegments;
Map<Byte, ArrayList<Byte>> secondSegments;
Map<Byte, FinalObject> thirdSegments;
where FinalObject is the fully assembled data type (e.g., Byte[3]). This provides efficient lookup by segment, but you'll need to iterate over the arrays to find the "next" group of segments to check. Roughly:
Byte[3] needle = ...;
Byte firstSeg = ...;
Byte secondSeg = ...;
Byte thirdSeg = ...;
for (Byte b1 : firstSegments.get(firstSeg)) {
if (b1.equals(secondSeg)) {
for (Byte b2 : secondSegments.get(b1)) {
if (b2.equals(thirdSeg)) {
return thirdSegments.get(b2); // found a match
}
}
}
}
It's not clear from your question, but if you're trying to decide whether a given Byte segment is in one of the arrays and don't care about iterating over them, it would be cleaner and more efficient to use a Set<Byte> instead of ArrayList<Byte>. Set provides a fast contains() method for this purpose.
What's the best way to return a Java Map using the JSON format?
My specific need is a key -> value association between a date and a number.
My concern is this: My structure basically contains N elements of the same type (a mapping between a date and a number), and I want to be able to quickly iterate through them in Javascript.
In XML, I would have:
<relation date='mydate' number='mynumber'/>
<relation date='mydate' number='mynumber'/>
...
<relation date='mydate' number='mynumber'/>
and I would use jQuery like this:
$(xml).find("relation").each(function() {
$(this).attr("date"); // the date
$(this).attr("number"); // the number
})
It's my first experience with JSON and I would like to know if I can do something similar.
Although I haven't tried it myself, the JSONObject of the Java implementation of JSON from json.org has a JSONObject(Map) constructor.
Once a JSON object is created from the Map, then a JSON string can be obtained by calling the toString method.
String myJson = "{ ";
for (String key : myMap.keySet())
myJson += key + " : " + "'" + myMap.get(key) + "',";
myJson += " } ";
I leave the last comma because it wont give us many problems. The javascript just ignores it.
Well, this respond your question but I guess that won't help much. Try posting a more specific one.