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
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.
I am reading the backup DynamoDB S3 bucket which has format for DynamoDB JSON.
I am trying to convert it into a normal JSON without the AttributeValue.
Original String
{
"id": {
"s": "someString"
},
"name": {
"b": "someByteBuffer"
},
"anotherId": {
"s": "someAnotherString"
},
"version": {
"n": "1"
}
}
Trying to convert to
{
"id": "someString",
"name": "someByteBuffer",
"anotherId": "someAnotherString",
"version": "1"
}
There are many answers which I referred to, but it doesn't convert into normal JSON, it gives me back the same JSON.
Here is what I tried:
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(inputJsonString);
final JacksonConverter converter = new JacksonConverterImpl();
Map<String, AttributeValue> map = converter.jsonObjectToMap(jsonNode);
Item item = ItemUtils.toItem(map);
Gson gson = new Gson();
System.out.println(gson.toJson(item.asMap()));
Also, when I was debugging, I wasn't able to create the Map properly. Map would contain key as "id", value as AttributeValue, but the AttributeValue would contain the string inside its own Map<String, AttributeValue> instead of inside String s
I feel I am missing something while creating the Map. Any pointers?
References on Stackoverflow:
Link 1
Link 2
What you're describing as the result sounds correct. If you look at the original JSON string, you have a list of key:value pairs where each value is another list of key:value pairs (length 1, but still a list).
To convert this to a single list of key:value pairs you need to write a map-reduce type of loop. Basically iterate the first map, take the key, then, from the second map (which is the value for the key you just recorded), just take the first entry's value (AttributeValue) and add that key:value pair into a new map (Map<String, AttributeValue>, which you define before the loop). That map you can then convert to JSON and it will result in the JSON string that you were expecting.
Hope that helps!
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...
I have probably easy question to advanced json/gson users. I get on request something like below:
[{
"1": {
"2": "6+"
}
},{
"1": []
}]
I try deserialize it to java object using gson but I meet problems. Gson reports to me :
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line X column Y
As I see the problem is that in first item '1' value is declared as an object and in second as and array. I don't have influence on generated JSON. Any idea how map it properly?
Maybe in gson I can add some hook and during parsing have influence what should be done with items? E.g. when for item "1" value is "[]" then do something different than when object with values is given?
After Arkain comment i must add:
In presented example still we have the same object - but it is presented differently :/ (once as empty array - other time as object)
From analysis I think that Object should be represented as e.g.
public class Example {
Map<String, Object> 1 = new Map<String,Object>;
...
}
but i don't know why when map is empty is represented in JSON as an empty array.
I don't know amount of positions and type of particular position in JSON collection.
To fix problem I use answer about custom deserializer from there:
Gson deserialize json with varying value types
I make my own deserializer class where I ignored array types (there are always empty and I do not need them):
public class InternalAttributeDeserializer implements JsonDeserializer<Attributes> {
#Override
public Attributes deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) throws JsonParseException {
Attributes attrs = new Attributes();
LinkedTreeMap<String, Object> map = context.deserialize(jsonElement, LinkedTreeMap.class);
for (String key : map.keySet()) {
Object obj = map.get(key);
if (obj instanceof LinkedTreeMap) {
#SuppressWarnings("unchecked")
LinkedTreeMap<String, String> imap = (LinkedTreeMap<String, String>) obj;
for (String ikey : imap.keySet()) {
AttributeInProduct iattr = new AttributeInProduct();
iattr.setPres_id(key);
iattr.setAttribute_id(ikey);
iattr.setValue(imap.get(ikey));
attrs.addAttribute(iattr);
}
}
}
return attrs;
}
}