Say I have a JSON file that looks like this:
{
"response" : [
{
"id" : "10",
"period" : "month",
"values" : [
{
"value" : 100,
"date" : "2013-05-10"
}
],
"parent" : "1"
},
{
"id" : "10",
"period" : "day",
"values" : [
{
"value" : {
"foo" : 10,
"bar" : 11,
"etc" : 4
},
"date" : "2013-05-10"
}
],
"parent" : "1"
},{
"id" : "13",
"period" : "year",
"values" : [
{
"value" : {
"info" : 1,
"pages" : 10,
"etc" : 4
},
"date" : "2013-05-10"
}
],
"parent" : "1"
}
]
}
Notice the 'values' part can either be a single value, or an object (which is unique).
I want to use the Jackson ObjectMapper to easily map this to a POJO.
What I have so far:
public class Response
{
List<ResponseEntry> response;
/*getters + setters */
public static class ResponseEntry
{
private String id;
private String period;
private String parent;
private List<Value> values;
/*setters + getters*/
public static class Value
{
private Object value;
private String date;
/*setters+getters*/
}
}
}
To map the response, I just specify the file I want and tell ObjectMapper to map to the 'Response' class
ObjectMapper mapper = new ObjectMapper();
Response r = mapper.readValues(json, Response.class);
This works, but is there a better way than just using 'Object' to hold 'value'? Since 'value' can be either a single value or an object, I'm having a bit of difficult figuring out what it should be. I'm certain there is a polymorphic way of handling this, but I've looked and couldn't find anything that worked. I'm pretty stuck and I would appreciate any help.
Unfortunately, with the structure of the JSON you are handling, the only way to deserialize it is to have the value attribute be type Object. However, once the JSON is deserialized, you can easily figure out whether value is an object or a single value.
Notice that JSON only supports five data types: objects (Map in java), arrays, strings, numeric and boolean. It looks like in your case, value would most likely be either a number or a map of numbers; then you have two possibilities to check for. Using a quick instanceof comparison, you should be able to figure out what type of value it is.
ObjectMapper mapper = new ObjectMapper();
Response r = mapper.readValues(json, Response.class);
Value val = r.response.get(0).values.get(0);
if (val.value instanceof Map)
; // multiple
else
; // single
Related
As you can see in the example below, the first item in the attributes array is an object consisting of two string properties. The second object consists of a string and array property. I would like to decode both of these types of JSON objects into a collection of Java objects.
How I can express this in a POJO java class to handle decoding JSON like this?
attributes:[
{
"attribute_code": "has_options",
"value": "0"
},
{
"attribute_code": "ewc_top_quick",
"value": [
{
"label": "Display",
"value": "12.5",
"suffix": "''"
},
{
"label": "Grafica Integrata",
"value": "1",
"suffix": ""
}
]
}
]
So, you can use Map<String, Object> fro this field.
class Attr {
private String attribute_code;
private Map<String, Object> value;
}
After this, you can work with this object.
Also, you can use #JsonAnySetter. It's something similar to the previous option.
And the best way to resolve your situation it's custom deserializer. I strongly recommended this option.
This question is about working with java REST and Jsonobjects. I have a #Get method that should return a Response and the json code below.
This method #Produces(MediaType.APPLICATION_JSON).I dont which code I have to write to return the Response + json below.
I think this returns a response + a list of items.
return Response.status(200).entity(arrayListFullOfItems).build()
But I dont know how to add the length part("length" :687) into it. The length field will be calculated based on a attribute of all the items.
The method should return this:
{
"item" :[
{
"id" : 1,
"name" : "Item1",
"bool" : true,
"reserveItem": []
},
{
"id" : 2,
"name" : "Item2",
"bool" : false,
"reserveItem": []
}
],
"length" :687
}
It's not possible like this: currently you're only returning the list. If you want to return more information, you should wrap the data you want to return in a new object and return that one.
e.g.
public class Data {
private List item;
private Integer length;
}
I am trying to serialize class object to json and deserialize json to class objects using jackson faster xml in scala. Here is my code.
var jsonDataString = objectMapper.writeValueAsString(nodeRepoList)
var deserializedData: List[NodeRepository] = objectMapper.readValue(jsonDataString, classOf[List[NodeRepository]]);
The json looks as follows.
[ {
"Operation" : "sample",
"Value" : "cool",
"TargetColumn" : "10",
"ClassName" : "RowFilter",
"DiagramId" : "2",
"NodeId" : "1"
}, {
"columnToInclude" : "sample",
"ClassName" : "ColumnFilter",
"DiagramId" : "2",
"NodeId" : "1"
} ]
While deserializing to the class object the output is as follows. The output is in Map.It shouldnot be in the Map type. It should be deserialized to class objects.
[Map(NodeId -> 1, ClassName -> RowFilter, TargetColumn -> 10, Value -> cool, Operation -> sample, DiagramId -> 2)]
Please let me know how to resolve the issue.
I recently had the same issue. Changing from List to Array solved my problem.
Instead of
classOf[List[NodeRepository]]
try using
classOf[Array[NodeRepository]]
Your result will be an array instead of a List, but the objects will be deserialized as NodeRepository instead of Map. Also converting the Array into a List in scala is pretty straight forward (toList method for example)
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 am trying to store all my written java files in a MongoDB and so far I've applied a schema like this (incomplete entry):
{
"_id" : ObjectId("52b861c230044fd08d6c27c4"),
"interfaces" : [
{
"methodInterfaces" : [
{
"name" : "add",
"name_lc" : "add",
"returnType" : "Integer",
"returnType_lc" : "integer",
"parameterTypes" : [
"Integer",
"Integer"
],
"parameterTypes_lc" : [
"integer",
"integer"
]
},
{
"name" : "isValid",
"name_lc" : "isvalid",
"returnType" : "Boolean",
"returnType_lc" : "boolean",
"parameterTypes" : [
"Integer",
"Double"
],
"parameterTypes_lc" : [
"integer",
"double"
]
}
],
"name" : "Calculator",
"name_lc" : "calculator",
"filename" : "Calculator.java",
"filename_lc" : "calculator.java"
}
],
"name" : "Calculator",
"name_lc" : "calculator",
"filename" : "Calculator",
"filename_lc" : "calculator",
"path" : "/xyz/Calculator.java",
"md5" : "6dec7e62c5e4f9060c7612c252cd741",
"lastModification" : ""
}
So far I am able to query a class that contains a method name, but I am not able to query a class with a certain name (let interfaces.name_lc="calculator") that must contain two methods with particular names (let's say "add" and "divide") which themselves should have two integer, resp. an integer and a double as parameters and both return an integer (don't question whether this is reasonable or not -- just for illustration purposes).
This is just one example; it can be more complex, of course.
I don't know how I can query for a particular class with method and specified parameters. I need to describe it sharp and want sharp results.
I am not able to construct a query, that would only return files like Calculator ( add(integer,integer):integer; divide(integer,double):integer; ). I get, e.g., OtherClass ( add():void; method(integer):integer; ), which is not what I want. I am trying this for days now, and maybe one can enlighten me, how to solve this in MongoDB. Thanks a lot in advance!
I'm not sure you'll be able to do this in MongoDB with your document structure. The issue I ran into is around the parameters - I'm assuming you care about the order of the parameters (i.e. doSomething(String, int) is not the same as doSomething(int, String)), and the query operators to check all the values in an array treat the array as a set, so a) order agnostic and b) eliminates duplicates (so doSomething(String, String) matches doSomething(String)) (this is because I was using the $all keyword, see the documentation, especially the note at the bottom).
I managed to get a large part of the query you wanted, however, which might point you in the right direction.
{ "$and" : [ //putting these in an "and" query means all parts have to match
{ "interfaces.methodInterfaces" :
{ "$elemMatch" : { "name" : "add"}} //this bit finds documents where the method name is "add"
} ,
{ "interfaces.methodInterfaces" :
{ "$elemMatch" : { "returnType" : "Integer"}} // This bit matches the return type
} ,
{ "interfaces.methodInterfaces.parameterTypes" :
{ "$all" : [ "Integer" , "Integer"]} //This *should* find you all documents where the parameter types matches this array. But it doesn't, as it treats it as a set
}
]}
If you're querying via the Java driver, this looks like:
BasicDBObject findMethodByName = new BasicDBObject("interfaces.methodInterfaces",
new BasicDBObject("$elemMatch", new BasicDBObject("name", "add")));
BasicDBObject findMethodByReturn = new BasicDBObject("interfaces.methodInterfaces",
new BasicDBObject("$elemMatch", new BasicDBObject("returnType", "Integer")));
BasicDBObject findMethodByParams = new BasicDBObject("interfaces.methodInterfaces.parameterTypes",
new BasicDBObject("$all", asList("Integer", "Integer")));
BasicDBObject query = new BasicDBObject("$and", asList(findMethodByName, findMethodByReturn, findMethodByParams));
DBCursor found = collection.find(query);
I haven't included matching the class name, as this didn't seem to be the tricky part - just build up another simple query for that an add it into the "$and".
Since the arrays to store parameter types are not giving what you want, I suggest you think about something a little more structured, although it's a bit unwieldy. Instead of
"parameterTypes" : [
"Integer",
"Integer"
]
Consider something like
"parameterTypes" : {
"param1" : "Integer",
"param2" : "Integer"
}
Then you won't be doing set operations, you can query each parameter individually. This means you'll also get them in the correct order.