I have this function to return a valid JSON response:
public static Result response() {
ObjectNode result = Json.newObject();
result.put("status", "OK");
result.put("response", "Hello ");
return ok(result);
}
But what I want is to server an Array of objects in "result" property like:
{
"status": "OK",
"response": {
"results": [
{
"key1": "value",
"key2": 90,
"key3": "value"
},
{
"key1": "value"
"key2": 90,
"key3": "value",
}
]
}
}
How can I do this? I need to use Java and Play!
The Play framework uses Jackson. Therefore, you may use Jackson proper:
private static final JsonNodeFactory NODE_FACTORY = JsonNodeFactory.instance;
// ...
final ArrayNode results = NODE_FACTORY.arrayNode();
ObjectNode oneResult;
oneResult = NODE_FACTORY.objectNode(); // or Json.newObject();
oneResult.put(...); // etc
results.add(result);
//rinse, repeat for all other result objects, then:
result.put("results", results);
I guess the Json class also has .newArray() and such. Have a look at Jackson's ObjectNode, ArrayNode. Note: as far as I can remember, Play uses Jackson 1.9.x, which is prehistoric...
But really, you should try and use Jackson's {de,}serialization.
I did not wait for your answer about what is Play!, so I write based on Gson.
Try use this class:
public class Result implements Serializable {
String status;
Response response;
class Response implements Serializable {
List<ListItem> results;
class ListItem implements Serializable {
String key1;
Integer key2;
String key3;
}
}
}
It 100% works on your json fragment. You can supplement it with the necessary fields.
And then you can use Gson:
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Result result = gson.fromJson(new FileReader(new File("json.json")), Result.class);
String json = gson.toJson(result);
System.out.println(json);
Prints:
{
"status": "OK",
"response": {
"results": [
{
"key1": "value",
"key2": 90,
"key3": "value"
},
{
"key1": "value",
"key2": 90,
"key3": "value"
}
]
}
}
Try in this direction.
How about returning an ArrayNode in the result, like:
public static Result foo() {
ArrayNode arrayNode = Json.newObject().putArray("bars");
arrayNode.add("hello");
arrayNode.add("world");
return ok(arrayNode);
}
Related
I am creating a crud form in which I am producing and consuming Json data.
Problem:
Json data I am producing is very dynamic. So I don't know how to map it to my pojo class.
What I have tried
1) Using jackson library, I created structure of my json data and
tried mapping with it. It failed as in data "**Keys**" are dynamic so mapping failed.
2) I searched and found JsonNode provided by Jackson, problem with
this is my json structure has key:[{},{}] structure like this
**key-->array of objects**, so I tried parsing it with json node but failed.
My Json Data
Type 1
{
"city_master": [
{
"citycode": [
"100",
"1130385"
]
},
{
"cityname": [
"London",
"1130383"
]
},
{
"statecode": [
"512",
"1130382"
]
}
]
}
Problem with structure is that key = "city_master" or any key in this format eg("citycode", "cityname" etc) is dynamic so can't create mapping pojo for this class.
Then I tried fixing the outer key as root and parse is as Json Node as
Type 2
{
"root": [
{
"citycode": [
"100",
"1130385"
]
},
{
"cityname": [
"London",
"1130383"
]
},
{
"statecode": [
"512",
"1130382"
]
}
]
}
In this structure I loose my key value, but I can store it else where.
With JsonNode (Type-2) I tried this
String jsonString = tdObj.getTempData(); // return's Json String
TempDataTblPojo obj = new ObjectMapper().readValue(jsonString, TempDataTblPojo.class);
JsonNode jsonNode = obj.getRoot();
System.out.println("Name = " + jsonNode);
This class TempDataTblPojo
public class TempDataTblPojo {
private JsonNode root;
public JsonNode getRoot() {
return root;
}
public void setRoot(JsonNode root) {
this.root = root;
}
}
It prints this
Name = [{"citycode":["100","1130385"]},{"cityname":["London","1130383"]},{"statecode":["512","1130382"]}]
Now how to parse this JsonNode, to get all this key-value's? Or is there is efficient or much more cleaner solution, I will be happy to accept.
Maybe this will help you.
class Pojo {
private List<PojoItem> root;
public List<PojoItem> getRoot() {
return root;
}
public void setRoot(List<PojoItem> root) {
this.root = root;
}
}
class PojoItem {
private Map<String, List<String>> items = new HashMap<>();
public Map<String, List<String>> getItems() {
return items;
}
#JsonAnySetter
public void setItem(String key, List<String> values) {
this.items.put(key, values);
}
}
And then you can get it from json using this:
Pojo result = objectMapper.readValue(json, Pojo.class);
Consider the following JSON File:
{
"version": "1.0",
"firstData": {
"meta": "this is string",
"version": "1"
},
"SecondData": {
"meta": ["string1", "string2", "string3"],
"version": "1"
},
"ThirdData": {
"meta": true,
"version": "1"
},
"FourthData": {
"meta": [true, false, false, true],
"version": "1"
},
"FifthData": {
"meta": [{
"meta": "string",
"version": "2"
},
{
"meta": ["string1","string2"],
"version": "2"
}]
"version": "1"
}
}
As seen, The "meta" attribute has different data type, sometimes it is String, sometimes it is ArrayOfString, sometimes Boolean etc.
Since my JSON file has several data,
I want it to follow the following Structure :
class information
{
String version;
HashMap<String,Data> details;
}
class Data
{
variable meta;
String version;
}
How do I create a corresponding POJO and deserialize it using Google GSON?
Just define your meta as JsonElement. Then you will have sort methods like: getAsString, getAsBoolean, getAsJsonObject, getAsJsonArray, ..., and also you are able to deserialize it again after you find out what is the type.
So your class could look like:
public class SomeClass {
private int version;
private JsonElement meta;
//getters and setters and other stuff
}
Edit: More elaboration and implementation
Define two classes: GeneralItem and GeneralData
class GeneralItem
{
public final int version;
public final JsonElement meta;
}
class GeneralData
{
public final String version;
public final Map<String, GeneralItem> items;
public GeneralData(String version, Map<String, GeneralItem> items)
{
this.version = version;
this.items = items;
}
}
And then we define a custom deserializer for our GeneralData:
class GeneralDataDeserializer implements JsonDeserializer<GeneralData>
{
#Override
public GeneralData deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
final JsonObject object = json.getAsJsonObject();
final String version = object.get("version").getAsString();
object.remove("version");
HashMap<String, GeneralItem> items = new HashMap<>(object.size());
for (Map.Entry<String, JsonElement> item : object.entrySet())
items.put(item.getKey(), context.deserialize(item.getValue(), GeneralItem.class));
return new GeneralData(version, items);
}
}
Finally registering the deserializer to our gson instance and getting the data:
final Gson gson = new GsonBuilder()
.registerTypeAdapter(GeneralData.class, new GeneralDataDeserializer())
.create();
final String json = "your json here";
final GeneralData data = gson.fromJson(json, GeneralData.class);
System.out.println(data.items.get("firstData").meta.getAsString());
//other parts you want
(Note that constructors, getter and setters, error checking, etc. are removed for the sake of brevity)
I have a List of Objects with multiple fields. Based on the API call, the List would be returned with only a specific set of fields. When I use transient - it does not serialize that particular field. But, that field should be returned for another API call. I am using Gson.
In the example below, based on the API, I wanted to print a list of Table instances with only E.g. "name" of the Table instances, or both "name" and "location", or just location. There could be 30 fields in the Table Object.
One way is to map it to a POJO for each scenario and then print it out. Is there a better way to do this? where you can select/choose/constrain which field gets serialized.
E.g.
package Testing;
import java.util.ArrayList;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class TestJson {
public static Gson obGson = new GsonBuilder().setPrettyPrinting().create();
public static void main(String[] args) {
ArrayList<Table> myTable = new ArrayList<Table>();
myTable.add(new Table("John", "Chicago"));
myTable.add(new Table("David", "Seattle"));
myTable.add(new Table("June", "Dallas"));
System.out.println(obGson.toJson(myTable));
}
}
class Table {
String name;
String location;
public Table (String _name, String _location) {
name = _name;
location = _location;
}
}
The output for the above looks like this. When API-1 is called then the output should like below.
[
{
"name": "John",
"location": "Chicago"
},
{
"name": "David",
"location": "Seattle"
},
{
"name": "June",
"location": "Dallas"
}
]
But when API-2 is called then the output should like below. Only return the fields that are approved for that API call.
[
{
"name": "John"
},
{
"name": "David"
},
{
"name": "June"
}
]
Similarly, the return could be managed based on the API call.
Implement ExclusionStrategy like
#RequiredArgsConstructor
public class FieldExclusionStrategy implements ExclusionStrategy {
#NonNull
private final Collection<String> serializedFields;
#Override
public boolean shouldSkipField(FieldAttributes f) {
if(serializedFields.contains(f.getName())) return false;
return true;
}
#Override
public boolean shouldSkipClass(Class<?> clazz) { return false; }
}
Use like
#Test
public void testShouldSkipField() {
Gson gson;
Table table = new Table();
Collection<String> serializedFields = new ArrayList<>();
ArrayList<Table> myTable = new ArrayList<Table>();
myTable.add(new Table("John", "Chicago"));
myTable.add(new Table("David", "Seattle"));
myTable.add(new Table("June", "Dallas"));
serializedFields.add("name");
gson = new GsonBuilder()
.setPrettyPrinting()
.addSerializationExclusionStrategy(
new FieldExclusionStrategy(serializedFields))
.create();
log.info("\n{}", gson.toJson(myTable));
serializedFields.add("location");
gson = new GsonBuilder()
.setPrettyPrinting()
.addSerializationExclusionStrategy(
new FieldExclusionStrategy(serializedFields))
.create();
log.error("\n{}", gson.toJson(myTable));
serializedFields.remove("name");
gson = new GsonBuilder()
.setPrettyPrinting()
.addSerializationExclusionStrategy(
new FieldExclusionStrategy(serializedFields))
.create();
log.error("\n{}", gson.toJson(myTable));
}
Above would log something like
2017-12-23 19:47:17.028 INFO org.example.gson.FieldExclusionStrategyTest:37 -
[
{
"name": "John"
},
{
"name": "David"
},
{
"name": "June"
}
]
2017-12-23 19:47:17.034 ERROR org.example.gson.FieldExclusionStrategyTest:44 -
[
{
"name": "John",
"location": "Chicago"
},
{
"name": "David",
"location": "Seattle"
},
{
"name": "June",
"location": "Dallas"
}
]
2017-12-23 19:47:17.035 ERROR org.example.gson.FieldExclusionStrategyTest:51 -
[
{
"location": "Chicago"
},
{
"location": "Seattle"
},
{
"location": "Dallas"
}
]
You need to build GSON again after changing list of serialized field names.
GSON caches internally the result - true|false - upon first call for some field name and does not query it again for cached field name.
And to add ExclusionStrategy you need to build GSON with GsonBuilder which then registers ExclusionStrategy (or many of them).
See also my question about this topic.
I'm working with a web service that enjoys making wheels. For a sequence of objects, instead of storing the data inside a JSON array, they make a new node for each index of the sequence.
{
"sequence": {
"0": {
"foo": "foo",
"bar": "bar",
"baz": "baz"
},
"1": {
"foo": "foo",
"bar": "bar",
"baz": "baz"
},
"2": {
"foo": "foo",
"bar": "bar",
"baz": "baz"
}
}
}
I was wondering if anyone had an elegant solution or sane approach to deserialize this into an array or collection of Sequence beans with jackson
public class SequenceElement {
String foo, bar, baz;
// Getters and setters below
}
Working with the sequence as a JsonNode is the best thing I can come up with atm, here is some untested sudo code.
ObjectMapper objectMapper = new ObjectMapper();
#JsonProperty("sequence")
public void setSequence(JsonNode sequence) {
List<SequenceElement> list = new ArrayList<SequenceElement>();
int i = 0;
while( sequence.get( String.valueOf(i) ) != null ) {
JsonNode element = sequence.get( String.valueOf(i) );
list.add( objectMapper.readValue( element, SequenceElement.class );
i += 1;
}
this.sequence = list;
}
IMO Map<String,Sequence> Should be Java equivalent for the JSON Object.
To extend on #SubirKumarSao's already correct answer, here is a way to get your sequence items as a list, in the same order as guaranteed by the data indices:
Data classes:
public class Sequence {
private String foo;
private String bar;
private String baz;
// Constructors, getters/setters
#Override
public String toString() {
return String.format("Sequence[foo=%s, bar=%s, baz=%s]", getFoo(),
getBar(), getBaz());
}
}
class SequenceHolder {
private Map<Integer, Sequence> sequence;
public SequenceHolder() {
sequence = new TreeMap<Integer, Sequence>();
}
// Other constructors, getters/setters
}
Main logic:
final String json = "JSON HERE";
final SequenceHolder holder = new ObjectMapper().readValue(json,
SequenceHolder.class);
System.out.println(holder.getSequence().values());
Tested with this modified version of your JSON (to illustrate ordering):
{
"sequence": {
"0": {
"foo": "foo0",
"bar": "bar0",
"baz": "baz0"
},
"1": {
"foo": "foo1",
"bar": "bar1",
"baz": "baz1"
},
"2": {
"foo": "foo2",
"bar": "bar2",
"baz": "baz2"
}
}
}
Output:
[Sequence[foo=foo0, bar=bar0, baz=baz0], Sequence[foo=foo1, bar=bar1, baz=baz1], Sequence[foo=foo2, bar=bar2, baz=baz2]]
As you can see, you get a list of items, in the same order as that guaranteed by your data indexes (the key being the use of a tree map).
I have the followed snipets of Json String:
{
"networks": {
"tech11": {
"id": "1",
"name": "IDEN"
},
"tech12": {
"id": "2",
"name": "EVDO_B"
}
}
}
I use some methods to convert this String to Object:
private static Gson mGson = new Gson();
...
public static WebObjectResponse convertJsonToObject(String jsonString) {
WebObjectResponse webObjectResponse = null;
if(jsonString != null && jsonString.length() > 1){
webObjectResponse = mGson.fromJson(jsonString, WebObjectResponse.class);
}
return webObjectResponse;
}
Where WebObjectResponse is class that should represent above mentioned String.
Its not complicated if I get static fields.
But in my case the values have different names: tech11, tech12 ....
I can use #SerializedName but its works in specific cases like convert "class" to "class_".
As you see networks Object defined as list of tech Objects but with different post-fix.
public class WebObjectResponse{
private DataInfoList networks = null;
}
This is static implementation, i defined 2 values tech11 and tech12 but next response might be techXX
public class DataInfoList {
private DataInfo tech11 = null;
private DataInfo tech12 = null;
}
public class DataInfo {
private String id = null;
private String name = null;
}
What is the good way to convert current Json String to Object where list of elements are Objects too and have different names?
Thank you.
Use a Map!
I would do the following
public class WebObjectResponse {
private Map<String, DataInfo> networks;
}
public class DataInfo {
private String id = null;
private String name = null;
}
// later
Gson gson = new Gson();
String json = "{\"networks\": {\"tech11\": { \"id\": \"1\",\"name\": \"IDEN\" }, \"tech12\": { \"id\": \"2\", \"name\": \"EVDO_B\" } }}";
WebObjectResponse response = gson.fromJson(json, WebObjectResponse .class);
For each object in json networks, a new entry will be added to the Map field of your class WebObjectResponse. You then reference them by techXX or iterate through the keyset.
Assuming a structure like this
{
"networks": {
"tech11": {
"id": "1",
"name": "IDEN"
},
"tech12": {
"id": "2",
"name": "EVDO_B"
},
"tech13": {
"id": "3",
"name": "WOHOO"
}, ...
}
}
We would need your class structure for more details.
As far as I am aware, I think you will need to have some mappings defined somewhere (I used xml's) and then try to match json with one of the mappings to create objects.
Google gson is good. I did it in Jackson
Also, converting objects should be trivial. But since you might have variable fields like tech11 and tech12 , you might want to store the "network" value as a string and then extract fields out of it when required.
Hope I could help.
Edit : Sotirious nails it.
Please use this link for converting SON Response to Java POJO class
http://www.jsonschema2pojo.org/