Java Rest Assured - how to sort JSON response
[
{
"name": "firstName",
"age": 22
},
{
"name": "AnotherName",
"age": 33
}
]
I have list of many objects - after deserlizlization to Java objects I want to SORT it based on age value - so the first shoulb be object with age 33.
First, create a POJO representing the deserialized object:
#Data
public class YourObject {
private String name;
private int age;
}
Then you can deserialize your JSON string to List<YourObject> by using Jackson's ObjectMapper
List<YourObject> list = new ObjectMapper().readValue(json, new TypeReference<List<YourObject>>(){});
Then use List.sort and Comparator to sort this list by descending order.
list.sort(Comparator.comparing(YourObject::getAge, Collections.reverseOrder()));
Related
I have class with field names:
private List<String> names;
Json that I'm getting looks like:
"names": [
{
"name": "a",
},
{
"name": "b",
},
{
"name": "c",
}
]
So I use custom serializing for transform this json to List:
#JsonProperty("names")
private void deserializeNames(List<Map<String, String>> json) {
names = json.stream().map(e -> e.get("name")).collect(Collectors.toList());
}
And this solution works, but when I will want to serialize objects of my class, new json will looks like:
"names": [
"a",
"b",
"c"
]
And my code for custom serializing won't work with it because it expects Map instead List
I tried to solve the problem using instanceof or deserialize list to map, but I think this is a wrong solution.
Is there any easy solutions for this problem?
You need not write custom Deserialiser for this,
You can define a class,
class Name {
#JsonProperty("name")
String name;
Name () {
}
}
You can use,
#JsonProperty("names")
private List<Name> names;
This will deserialise automatically. While serialising it will do the same.
I want to deserialize the following JSON (in the original there are about 100 Exchanges with dynamic values):
{
"Exchange1": {
"EUR": [
"CNY",
"USD"
],
"INR": [
"USD",
"CNY"
]
},
"Exchange2": {
"BRL": [
"EUR",
"USD",
"INR"
],
"JPY": [
"USD",
"EUR",
"CNY"
]
},
....
}
I am using http://www.jsonschema2pojo.org/ but it is generating a Java class taking literal values ("Exchange1", "EUR", etc) while I need to iterate this no matter what is the dynamic String value:
How can I describe this JSON with Java?
You cannot have POJOs here (in sane sense), but people tend to use POJO-generators that do not do ahead analysis even for dynamic objects.
"Dynamic" objects should be typically mapped using java.util.Map (ordered implementation) + unique values can be mapped using java.util.Set (ordered implementation).
Thus, if you have a custom enumeration for the currencies, say something like
enum Currency {
BRL,
CNY,
EUR,
INR,
JPY,
USD,
}
then you can easily define the mapping without any POJOs that do not look applicable here at all:
private static final Type exchangesType = new TypeToken<Map<String, Map<Currency, Set<Currency>>>>() {
}.getType();
final Map<String, Map<Currency, Set<Currency>>> exchanges = gson.fromJson(jsonReader, exchangesType);
System.out.println(exchanges);
So the trivial toString() output will be as follows:
{Exchange1={EUR=[CNY, USD], INR=[USD, CNY]}, Exchange2={BRL=[EUR, USD, INR], JPY=[USD, EUR, CNY]}}
If you don't like the idea of having the Currency enumeration (you must always keep it up to date with recompilation, etc), then you can simply declare the currency markers as java.lang.String and get the same result:
private static final Type exchangesType = new TypeToken<Map<String, Map<String, Set<String>>>>() {
}.getType();
final Map<String, Map<String, Set<String>>> exchanges = gson.fromJson(jsonReader, exchangesType);
System.out.println(exchanges);
I am trying to serialize a list of JSON blobs and put certain keys into a HashTable during the serialization. Here is an example of my JSON:
[
{
"name": "sally",
"id": 1,
"eye_color": "green"
},
{
"name": "jack",
"id": 2,
"eye_color": "blue"
},
{
"name": "jane",
"id": 3,
"eye_color": "brown"
}
]
What I am looking for specifically is a POJO (or set of POJOs) which can serialize the above JSON like so with Jackson assuming the above JSON is in a file called above_json.json:
MyPOJO pojo = objectMapper.readValue(new File("above_json.json"), MyPOJO.class);
I want the result of the serialization to give me a HashTable (or an Object which encapsulates the HashTable) where the HashTable key is the value of name and the Hashtable value is the value of the corresponding id above.
Assuming we serialized the above JSON in this fashion, I would want to access the HashTable like so:
myTable.get("jane")
result: 3
myTable.get("jack")
result: 2
myTable.get("Jill")
result: null
I know how to serialize basic JSON with Jackson. I have an example like below:
JSON Input:
"Parameter":{
"Name":"Parameter-Name",
"Value":"Parameter-Value"
}
POJO to serialize above simple JSON:
public class Parameter {
#JsonProperty("Name")
public String name;
#JsonProperty("Value")
public String value;
}
But obviously this type of setup does not put the results into a HashTable. I need a POJO like what I have in this example which will serialize JSON directly into a HashTable
I don't think that is possible.
You serialize this json into a list of pojos, and have a utility function to generate the hashtable in the way you desire from the list of pojos.
Create a POJO for holding the properties you are interested in.
#JsonIgnoreProperties(ignoreUnknown = true)
private static class MyPOJO {
#JsonProperty("name")
private String name;
#JsonProperty("id")
private Integer id;
public Integer getId() {
return id;
}
public String getName() {
return name;
}
}
Deserialize the contents of the file into List<MyPOJO>
List<MyPOJO> myPOJO = mapper.readValue(new File(".."), new TypeReference<List<MyPOJO>>(){});
Stream the contents of the map to construct a map whose key is the name and value is the id.
Map<String, Integer> map = myPOJO.stream()
.collect(Collectors.toMap(MyPOJO::getName, MyPOJO::getId));
First of all, you probably don't want to use a HashTable, as it's considered to be an obsolete type (see here).
Either use a HashMap or if you want thread safety, a ConcurrentHashMap or a thread-unsafe Map backed by Collections.synchronized[...] and referenced to within synchronized statements.
Secondly, you can use a TypeReference to de-serialize as your desired type.
Finally, your JSON's syntax is incorrect: it starts with a square bracket ([) and ends with a curly bracket (}), which is technically unparseable.
Assuming you want an array of Maps here (e.g. HashMap<String, String>[]), here is some suitable code, provided you replace the last curly bracket with a square one:
// the map array
Map<String, String>[] map = null;
map = om.readValue(yourFile, new TypeReference<HashMap<String, String>[]>() {});
// prints the de-serialized contents
System.out.println(Arrays.toString(map));
Edit
Since you have now edited your JSON to remove the first square bracket and replace it with a curly bracket, no you can't parse as a Map as is.
Edit 2
Since you have now re-edited your JSON to feature square brackets once again instead of curly brackets in the wrapping object, you can once again de-serialize as a Map[]. Until the next edit, I guess...
when using the javax json ObjectBuilder to build json, the output json string contains "value" and "num" in the json string. my web service is throw serialization error when the json contains "value" and "num". any one know why the output have "value" and "num"?
example:
JsonObject addProductRequest = Json.createObjectBuilder()
.add("OrderID", orderId)
.add("Product", productId)
.add("Quantity", qty)
.add("access_token", access_token)
.build();
output:
{
"OrderID": {
"num": 15498
},
"ProductID": {
"num": 20
},
"Quantity": {
"num": 1
},
"access_token": {
"value": "1f6c689d-6956-4f8e-b259-9030d57bec4b"
}
}
when I switch to using google.gson.JsonObject, the output dont have the "value" and "num" string, which my web service accepts and every thing seems to work fine.
example
com.google.gson.JsonObject addProductRequest = new com.google.gson.JsonObject();
addProductRequest.addProperty("OrderID", orderId);
addProductRequest.addProperty("Product", productId);
addProductRequest.addProperty("Quantity", qty);
addProductRequest.addProperty("access_token", access_token);
output:
{ "OrderID": 15499, "Product": 20, "Quantity": 1, "access_token": "3241cfd4-7b6c-4eac-b2bb-9b2b0c780831"}
Rest Assured seems to use Gson to serialize POJOs (which is what you should be using as response entities) to the response body.
Gson doesn't know anything about javax.json. The implementation of javax.json that you are using basically has this format for its JsonObject:
private static final class JsonObjectImpl extends AbstractMap<String, JsonValue> implements JsonObject {
private final Map<String, JsonValue> valueMap; // unmodifiable
Since this is a Map, Gson uses special serializing, iterating through its entrySet and using each Entry as a JSON key-value pair (within a JSON object).
In this case, the entrySet returns
#Override
public Set<Entry<String, JsonValue>> entrySet() {
return valueMap.entrySet();
}
where the valueMap contains all the values you added with add in your builder. For example, for
.add("OrderID", 1)
it will have added an entry with the String key OrderID and the JsonValue value of
// Optimized JsonNumber impl for int numbers.
private static final class JsonIntNumber extends JsonNumberImpl {
private final int num;
Notice the num field.
So Gson will now see a value of this JsonIntNumber type. It considers it a POJO and so serializes it as a JSON object with its fields as key-value pairs. It therefore produces
{
"num": 15498
}
com.google.gson.JsonObject is a known type to Gson. It knows that it is special and not a custom POJO type. It can therefore write it directly, instead of having to serialize it further.
This is similar to a question which I answered here:
Returning JsonObject using #ResponseBody in SpringMVC
I have a list of categories coming back from a web request, in JSON format. An example might be:
"categories":[["Descriptive Cat 1 Name","cat1label"]]
How would that be represented in the object? I currently have an object called Category, and am using it like:
private List<Category> categories;
The Category object looks something like:
class Category {
private String descrName;
private String label;
.. getters and setters..
}
When attempting to decode with GSON I get this eror:
01-27 21:44:46.149: ERROR/AndroidRuntime(843): com.google.gson.JsonParseException: Expecting array but found object: Category#437d1ff8
Any suggestions? I would also be OK having those come back as a map, although instead of K,V in the JSON results they would be V,K, could it be mapped that way?
It does work if I ditch the Category object all together, and just map it as:
private List<List<String,String>> categories;
But is there a better way to represent that data?
Nick
As #Dante617 correctly pointed, your JSON representation is not correct. The correct representation is
{
"categories": [
{"descrName":"Descriptive Cat Name 1", "label": "cat1Label"},
{"descrName":"Descriptive Cat Name 2", "label": "cat2Label"}
]
}
Now, this can be thought of as a map of "categories" title and list of Category objects. So, the Java object, that maps it, will be Map<String, List<Category>>
If you somehow reformat your string correctly like the one above. Here is how you would parse.
String categories = "{\"Categories\":[{\"descrName\":\"Descriptive Cat 1 Name\",\"label\":\"cat1label\"}, {\"descrName\":\"Descriptive Cat 2 Name\",\"label\":\"cat2label\"}]}";
Gson gson = new Gson();
Type type = new TypeToken<Map<String, List<Category>>>() {}.getType();
Map<String, List<Category>> l = gson.fromJson(categories, type);
System.out.println("l: " + l);
If your Java object looks like this
public class Category {
private String descrName;
private String label;
//no need of getters and setters. Reflection, baby! :)
#Override
public String toString() {
return "<Name:"+descrName+", label:"+label+">";
}
}
The output will show like this
l: {Categories=[<Name:Descriptive Cat 1 Name, label:cat1label>, <Name:Descriptive Cat 2 Name, label:cat2label>]}
I'm not familiar with GSON, but I'm not sure how the application could map the strings to the fields in your object. It seems like you want a JSON structure more like:
"categories": [
{"descrName":"Descriptive Cat Name 1", "label": "cat1Label"},
{"descrName":"Descriptive Cat Name 2", "label": "cat2Label"}
]
That might help in being able to dynamically create the Java objects.
In contrary to what others think, that's not invalid JSON. The [[]] is just a two-dimensional array. In Java terms, it maps as follows:
String json = "{\"categories\":[[\"Descriptive Cat 1 Name\",\"cat1label\"]]}";
Map<String, String[][]> map = new Gson().fromJson(json, new TypeToken<Map<String, String[][]>>(){}.getType());
// ...
or
String json = "{\"categories\":[[\"Descriptive Cat 1 Name\",\"cat1label\"]]}";
Map<String, List<List<String>>> map = new Gson().fromJson(json, new TypeToken<Map<String, List<List<String>>>>(){}.getType());
// ...
Thanks for the input folks. Unfortunately this is a public web service I'm utilizing (the Yelp v2 API) and I can't change the format of the data they are returning. This is what I stuck with for now which is working fine:
private List<List<String>> categories;