I have 3 JSON payloads: A, B and C. I need to find out if payload A contains B and C.
When B is compared against A, I need the result to be true.
When C is compared against A, I need the result to be false
as college key does not exist in payload A.
Note: Below JSON payloads are just examples and can have different structure and values.
Payload A:
{
"id": "1",
"search": {
"name": "Testing",
"age": "25",
"school": "sacred heart"
},
"Address": {
"street": "Abcedf",
"road": "4th cross",
"city": "bangalore"
}
}
Payload B
{
"id": "1",
"search": {
"name": "Testing"
},
"Address": {
"street": "Abcedf",
"road": "4th cross"
}
}
Payload C
{
"id": "1",
"search": {
"name": "Testing",
"college": "global"
},
"Address": {
"street": "Abcedf",
"road": "4th cross"
}
}
First step would be to create Java objects from your Json. You can use Gson, Jackson or any other library of your choice. For this example I have used Gson.
Your class definition
private class JsonObject {
String id;
Map search;
#SerializedName(value="Address")
Map address;
// getter and setter
}
Parsing objects ( a,b and c are your Json Strings )
Gson gson = new Gson();
JsonObject objectA = gson.fromJson( a, JsonObject.class);
JsonObject objectB = gson.fromJson( b, JsonObject.class);
JsonObject objectC = gson.fromJson( c, JsonObject.class);
For the actual comparison there are many ways to accomplish what you need. One way would be to implement your own method for comparing the objects
private static boolean check( JsonObject firstObject, JsonObject secondObject ) {
return firstObject.getAddress().entrySet().containsAll( secondObject.getAddress().entrySet() )
&& firstObject.getSearch().entrySet().containsAll( secondObject.getSearch().entrySet() );
}
Call the method
System.out.println( check ( objectA, objectB ) );
System.out.println( check ( objectA, objectC ) );
Result
true
false
Your can, of course create your own logic to compare your Maps inside the objects. Take a look at Java Collections Framework or the Guava library which offers some handy utility methods for working with Collections.
You can utilise JsonPointer to implement contains method. A.contains(B) method returns true when object A contains all pointers which has object B and all values are the same. Two objects (A and B) are equal when A.contains(B) and B.contains(A). From definition: A.contains(A) returns true for every A.
Simple implementation could look like below:
import com.fasterxml.jackson.core.JsonPointer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class JsonPointersApp {
public static void main(String[] args) throws IOException {
File aJsonFile = new File("./resource/a.json").getAbsoluteFile();
File bJsonFile = new File("./resource/b.json").getAbsoluteFile();
File cJsonFile = new File("./resource/c.json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
JsonPayload payloadA = new JsonPayload(mapper.readTree(aJsonFile));
JsonPayload payloadB = new JsonPayload(mapper.readTree(bJsonFile));
JsonPayload payloadC = new JsonPayload(mapper.readTree(cJsonFile));
System.out.println("JSON A:" + payloadA);
System.out.println("JSON B:" + payloadB);
System.out.println("JSON C:" + payloadC);
System.out.println("A contains B:" + payloadA.contains(payloadB));
System.out.println("A contains C:" + payloadA.contains(payloadC));
System.out.println("B contains C:" + payloadB.contains(payloadC));
System.out.println("C contains B:" + payloadC.contains(payloadB));
System.out.println("A contains A:" + payloadA.contains(payloadA));
}
}
class JsonPayload {
private final JsonNode root;
private final List<JsonPointer> pointers = new ArrayList<>();
JsonPayload(JsonNode root) {
this.root = Objects.requireNonNull(root);
findPointers(this.root, "");
}
public boolean contains(JsonPayload other) {
//If number of pointers are different, JSON payloads are also different
if (this.pointers.size() < other.pointers.size()) {
return false;
}
// If pointers are not the same
if (!this.pointers.containsAll(other.pointers)) {
return false;
}
// check values
return other.pointers
.stream()
.allMatch(p -> this.root.at(p).equals(other.root.at(p)));
}
private void findPointers(JsonNode node, String path) {
if (node.isObject()) {
node.fields().forEachRemaining(entry -> findPointers(entry.getValue(), path + "/" + entry.getKey()));
} else if (node.isArray()) {
final int size = node.size();
for (int i = 0; i < size; i++) {
findPointers(node.get(i), path + "/" + i);
}
} else {
pointers.add(JsonPointer.compile(path));
}
}
#Override
public String toString() {
return pointers.toString();
}
}
Above code prints:
JSON A:[/id, /search/name, /search/age, /search/school, /Address/street, /Address/road, /Address/city]
JSON B:[/id, /search/name, /Address/street, /Address/road]
JSON C:[/id, /search/name, /search/college, /Address/street, /Address/road]
A contains B:true
A contains C:false
B contains C:false
C contains B:true
A contains A:true
Related
I actually have a Class named "Content" like that :
public class Content {
private String Pame;
private String Tlue;
private String Ced;
private String Cnce;
#Override
public String toString() {
return "...";
}
}
On the other side I have a list of object of type "Content" with multiple objects in it.
My goal is to return a json formatted like this one:
There may be multiple values in the "content field", it's why there is [].
{
"result": "ok",
"content": [{
"pame": "value1",
"tlue": "value2",
"ced": "value3",
"cnce": "1"
}]
}
for(int i = 0; i < list.size(); i++){
String MyLongString = list.get(i).toString;
}
So my problem is :
How can I create the structure shown with the toString and the boucle For ?
How the "," at the end of each object can be put, without putting it at the last object ?
For information : I use Gson in my project
Thanks for helping
I am a newbie to android and I have a JSON file with dynamic key like this:
{
"x": {
"a": {
"1": [1,2,3,4],
"2": [1,2,3,4]
},
"b": {
"1": [1,2,3,4],
"2": [1,2,3,4]
}
},
"y": {
"a": {
"1": [1,2,3,4],
"2": [1,2,3,4]
},
"b": {
"1": [1,2,3,4],
"2": [1,2,3,4]
}
},
"z": {
"a": {
"1": [1,2,3,4],
"2": [1,2,3,4]
},
"b": {
"1": [1,2,3,4],
"2": [1,2,3,4]
}
}
}
I parsed it successfully by JSONObject but I have to loop by keys Iterator on x, y, z. For each time, I have to loop on a, b and the same for "1" and "2". I think it's not a good solution. I created models for them like this:
Class XYZ {
private String name; // "x", "y", "z" value
private ArrayList<ABC> abcList;
}
Class ABC {
private String name; // "a", "b", "c"
private ArrayList<Item> itemList;
}
Class Item{
private String ID; // "1", "2"
private int[] valueArray;
}
Can anyone help me to parse this json by Gson, I think it looks more professional :D. Thank you so much
Your models cannot map your JSON just because Gson default configuration clearly gets them unmatched.
You can have two "default" ways:
static
... since you didn't really mention why your JSON is considered dynamic:
final class XYZ {
final ABC x = null;
final ABC y = null;
final ABC z = null;
}
final class ABC {
final OneTwo a = null;
final OneTwo b = null;
}
final class OneTwo {
#SerializedName("1")
final List<Integer> one = null;
#SerializedName("2")
final List<Integer> two = null;
}
Example:
try ( final Reader reader = getPackageResourceReader(Q43695739.class, "dynamic.json") ) {
final XYZ xyz = gson.fromJson(reader, XYZ.class);
System.out.println(xyz.x.b.two);
}
dynamic (by deserialization)
... assuming your keys are dynamic, but the structure remains the same:
private static final Type stringToStringToStringToIntegerListType = new TypeToken<Map<String, Map<String, Map<String, List<Integer>>>>>() {
}.getType();
try ( final Reader reader = getPackageResourceReader(Q43695739.class, "dynamic.json") ) {
final Map<String, Map<String, Map<String, List<Integer>>>> m = gson.fromJson(reader, stringToStringToStringToIntegerListType);
System.out.println(m.get("x").get("b").get("2"));
}
dynamic (by JSON trees)
Another true dynamic approach that may be helpful for some scenarios. Also note that JSONObject is not in the Gson realm: you probably might have imported this one from the org.json package. Gson uses camel-cased names like JsonElement, JsonObject, etc.
try ( final Reader reader = getPackageResourceReader(Q43695739.class, "dynamic.json") ) {
final JsonElement jsonElement = gson.fromJson(reader, JsonElement.class)
.getAsJsonObject()
.getAsJsonObject("x")
.getAsJsonObject("b")
.getAsJsonArray("2");
System.out.println(jsonElement);
}
The first and the second examples produce java.util.List instances
[1, 2, 3, 4]
The third example returns a JsonArray instance with a slightly different toString implementation:
[1,2,3,4]
I have a JSON record that looks like this:
{"ActionRecord": {
"101": {
"Desc": "string 1",
"Done": 1,
"MaxTimes": 2,
"Point": 30,
"Times": 4
},
"102": {
"Desc": "string 2",
"Done": 1,
"MaxTimes": 3,
"Point": 15,
"Times": 13
},
"103": {
"Desc": "string 3.",
"Done": 1,
"MaxTimes": 5,
"Point": 15,
"Times": 24
}, ... }
I can get Jackson to parse this if i create a hacky intermediate class that contains a field for each number, and then use something like this in the class:
#JsonProperty( value = "101" )
public MyClass hundred_one;
#JsonProperty( value = "102" )
public MyClass hundred_two;
#JsonProperty( value = "103" )
public MyClass hundred_three;
But I have to type out all the expected values, so it would be much easier to be able to use an array list of objects, and insert the numeric id into the POJO with Jackson's mapper.
Is there a way have Jackson automatically map it into a class like this? :
public enum ActionRecord {
Something ( "101" ),
SomethingElse( "102" ),
AnotherSomething ( "103" ),
;
String _id;
EK_DailyTaskInfo_ActionRecord( String id )
{
_id = id;
}
public String getId()
{
return _id;
}
public String Desc; // "some string.",
public boolean Done; // 1,
public int Times; // 4
public int MaxTimes; // 2,
public int Point; // 30,
}
It does not have to be an enum this was just something I was trying before I gave up
Jackson can decode it into a Map<String, Record> for you, e.g.
public class Record {
public String Desc; // "some string.",
public boolean Done; // 1,
public int Times; // 4
public int MaxTimes; // 2,
public int Point; // 30,
}
public class ActionRecords {
public Map<String, Record> ActionRecord
}
well I am using GSON library in shown example, Android has it's own api to handle the JSON where a iterator is very useful, code is also available on github
What i want to propose is that you should read all the keys with respect to it's key's and get the JsonObject from there, you you have a JsonList which is not an array this is what you can do
JsonParser parser = new JsonParser();
JsonElement element = parser.parse(result); // result is your json data
JsonObject obj = element.getAsJsonObject();
System.out.println(obj.toString());
JsonObject jsonObject = obj.getAsJsonObject("ActionRecord"); // this will get the JsonObject with the key ActionRecord
System.out.println(jsonObject);
Set<Map.Entry<String, JsonElement>> stringSet = jsonObject.entrySet(); // this will map all the JsonObject with it's keys
for (Map.Entry<String, JsonElement> key :stringSet) {
System.out.println(jsonObject.getAsJsonObject(key.getKey()).toString());
}
Once you have the key with it's corresponding JSONObject, you can create populate your own type for that object.
well this is for Gson, you might want to look for equivalent of this in Jackson
output
{"Desc":"string 1","Done":1,"MaxTimes":2,"Point":30,"Times":4}
{"Desc":"string 2","Done":1,"MaxTimes":3,"Point":15,"Times":13}
{"Desc":"string 3.","Done":1,"MaxTimes":5,"Point":15,"Times":24}
Using the Gson library, how do I convert a JSON string to an ArrayList of a custom class JsonLog? Basically, JsonLog is an interface implemented by different kinds of logs made by my Android app--SMS logs, call logs, data logs--and this ArrayList is a collection of all of them. I keep getting an error in line 6.
public static void log(File destination, JsonLog log) {
Collection<JsonLog> logs = null;
if (destination.exists()) {
Gson gson = new Gson();
BufferedReader br = new BufferedReader(new FileReader(destination));
logs = gson.fromJson(br, ArrayList<JsonLog>.class); // line 6
// logs.add(log);
// serialize "logs" again
}
}
It seems the compiler doesn't understand I'm referring to a typed ArrayList. What do I do?
You may use TypeToken to load the json string into a custom object.
logs = gson.fromJson(br, new TypeToken<List<JsonLog>>(){}.getType());
Documentation:
Represents a generic type T.
Java doesn't yet provide a way to represent generic types, so this class does. Forces clients to create a subclass of this class which enables retrieval the type information even at runtime.
For example, to create a type literal for List<String>, you can create an empty anonymous inner class:
TypeToken<List<String>> list = new TypeToken<List<String>>() {};
This syntax cannot be used to create type literals that have wildcard parameters, such as Class<?> or List<? extends CharSequence>.
Kotlin:
If you need to do it in Kotlin you can do it like this:
val myType = object : TypeToken<List<JsonLong>>() {}.type
val logs = gson.fromJson<List<JsonLong>>(br, myType)
Or you can see this answer for various alternatives.
Your JSON sample is:
{
"status": "ok",
"comment": "",
"result": {
"id": 276,
"firstName": "mohamed",
"lastName": "hussien",
"players": [
"player 1",
"player 2",
"player 3",
"player 4",
"player 5"
]
}
so if you want to save arraylist of modules in your SharedPrefrences so :
1- will convert your returned arraylist for json format using this method
public static String toJson(Object jsonObject) {
return new Gson().toJson(jsonObject);
}
2- Save it in shared prefreneces
PreferencesUtils.getInstance(context).setString("players", toJson((.....ArrayList you want to convert.....)));
3- to retrieve it at any time get JsonString from Shared preferences like that
String playersString= PreferencesUtils.getInstance(this).getString("players");
4- convert it again to array list
public static Object fromJson(String jsonString, Type type) {
return new Gson().fromJson(jsonString, type);
}
ArrayList<String> playersList= (ArrayList<String>) fromJson(playersString,
new TypeToken<ArrayList<String>>() {
}.getType());
this solution also doable if you want to parse ArrayList of Objects
Hope it's help you by using Gson Library .
Why nobody wrote this simple way of converting JSON string in List ?
List<Object> list = Arrays.asList(new GsonBuilder().create().fromJson(jsonString, Object[].class));
Kotlin
data class Player(val name : String, val surname: String)
val json = [
{
"name": "name 1",
"surname": "surname 1"
},
{
"name": "name 2",
"surname": "surname 2"
},
{
"name": "name 3",
"surname": "surname 3"
}
]
val typeToken = object : TypeToken<List<Player>>() {}.type
val playerArray = Gson().fromJson<List<Player>>(json, typeToken)
OR
val playerArray = Gson().fromJson(json, Array<Player>::class.java)
If you want to use Arrays, it's pretty simple.
logs = gson.fromJson(br, JsonLog[].class); // line 6
Provide the JsonLog as an array JsonLog[].class
If you want convert from Json to a typed ArrayList , it's wrong to specify the type of the object contained in the list. The correct syntax is as follows:
Gson gson = new Gson();
List<MyClass> myList = gson.fromJson(inputString, ArrayList.class);
Let's say, You have a string like this.
"[{"id":2550,"cityName":"Langkawi","hotelName":"favehotel Cenang Beach - Langkawi","hotelId":"H1266070"},
{"id":2551,"cityName":"Kuala Lumpur","hotelName":"Metro Hotel Bukit Bintang","hotelId":"H835758"}]"
Then you can covert it to ArrayList via Gson like
var hotels = Gson().fromJson(historyItem.hotels, Array<HotelInfo>::class.java).toList()
Your HotelInfo class should like this.
import com.squareup.moshi.Json
data class HotelInfo(
#Json(name="cityName")
val cityName: String? = null,
#Json(name="id")
val id: Int? = null,
#Json(name="hotelId")
val hotelId: String? = null,
#Json(name="hotelName")
val hotelName: String? = null
)
I am not sure about gson but this is how you do it with Jon.sample hope there must be similar way using gson
{
"Players": [
"player 1",
"player 2",
"player 3",
"player 4",
"player 5"
]
}
===============================================
import java.io.FileReader;
import java.util.List;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
public class JosnFileDemo {
public static void main(String[] args) throws Exception
{
String jsonfile ="fileloaction/fileName.json";
FileReader reader = null;
JSONObject jsb = null;
try {
reader = new FileReader(jsonfile);
JSONParser jsonParser = new JSONParser();
jsb = (JSONObject) jsonParser.parse(reader);
} catch (Exception e) {
throw new Exception(e);
} finally {
if (reader != null)
reader.close();
}
List<String> Players=(List<String>) jsb.get("Players");
for (String player : Players) {
System.out.println(player);
}
}
}
In Kotlin
For sending : If you send Arraylist
Gson().toJson(arraylist)
For receiving: If you receive ArrayList
var arraylist = Gson().fromJson(argument, object : TypeToken<ArrayList<LatLng>>() {}.type)
For sending : If you send ModelClass( e.g. LatLngModel.class)
var latlngmodel = LatlngModel()
latlngmodel.lat = 32.0154
latlngmodel.lng = 70.1254
Gson().toJson(latlngModel)
For receiving: If you receive ModelClass
var arraylist = Gson().fromJson(argument,LatLngModel::class.java )
I have the following JSON:
{
"registration": {
"name": "Vik Kumar",
"first_name": "Vik",
"last_name": "Kumar",
"bloodGroup": "B-",
"gender": "male",
"birthday": "10\/31\/1983",
"email": "vik.ceo\u0040gmail.com",
"cellPhone": "1234123456",
"homePhone": "1234123457",
"officePhone": "1234123458",
"primaryAddress": "jdfjfgj",
"area": "jfdjdfj",
"location": {
"name": "Redwood Shores, California",
"id": 103107903062719
},
"subscribe": true,
"eyePledge": false,
"reference": "fgfgfgfg"
}
}
I am using the following code to parse it:
JsonNode json = new ObjectMapper().readTree(jsonString);
JsonNode registration_fields = json.get("registration");
Iterator<String> fieldNames = registration_fields.getFieldNames();
while(fieldNames.hasNext()){
String fieldName = fieldNames.next();
String fieldValue = registration_fields.get(fieldName).asText();
System.out.println(fieldName+" : "+fieldValue);
}
This works fine and it print all the values except for location which is kind of another level of nesting. I tried the same trick as above code to pass json.get("location") but that does not work. Please suggest how to make it work for location.
You need to detect when you are dealing with a (nested) Object using JsonNode#isObject:
public static void printAll(JsonNode node) {
Iterator<String> fieldNames = node.getFieldNames();
while(fieldNames.hasNext()){
String fieldName = fieldNames.next();
JsonNode fieldValue = node.get(fieldName);
if (fieldValue.isObject()) {
System.out.println(fieldName + " :");
printAll(fieldValue);
} else {
String value = fieldValue.asText();
System.out.println(fieldName + " : " + value);
}
}
}
Thus, when you reach an object, such as location, you'll call the printAll recursively to print all its inner values.
org.codehaus.jackson.JsonNode json = new ObjectMapper().readTree(jsonString);
org.codehaus.jackson.JsonNode registration_fields = json.get("registration");
printAll(registration_fields);
Since location is nested within registration, you need to use:
registration_fields.get("location");
to get it. But isn't it already processed by the while-loop, why do you need to get it separately?