Why this does not work?
public static class MyBean extends HashMap<String, String> {
public String city;
}
/**
* #param args
*/
public static void main(String[] args) {
MyBean bean = new MyBean();
bean.city = "some city";
Gson gson = new Gson();
String json = gson.toJson(bean);
System.out.println(json);
}
Why I dont see city value in json?
That's because instances implementing Map have special treatment by Gson. By default only its entry set will be serialized. You need to create a custom serializer which serializes both the entryset and the bean properties of interest separately.
E.g.
public class MyBeanSerializer implements JsonSerializer<MyBean> {
#Override
public JsonElement serialize(MyBean myBean, Type type, JsonSerializationContext context) {
JsonObject object = new JsonObject();
object.add("map", context.serialize(new HashMap<String, String>(myBean)));
object.add("city", context.serialize(myBean.city));
return object;
}
}
Which can be used as follows:
Gson gson = new GsonBuilder().registerTypeAdapter(MyBean.class, new MyBeanSerializer()).create();
String json = gson.toJson(bean);
System.out.println(json);
Update: hmm, as per the comment on the question (you should actually have posted it on the answer so that I will be notified immediately), the context.serialize(myBean.entrySet()) didn't seem to work out. And you're right, I just did a local test and I got the same exception. I tried adding a TypeToken on Set<Entry<String, String>>, but that ends up with an empty entryset somehow. Wrapping it in another map did work for me. I've updated the line in the answer.
Related
I currently have a custom serialiser. Purpose of my custom serialiser is to format my JSON object from this: {"id":["21","22", 23"]} to this {"id":"21,22,23"}.
My current implementation of my custom serialiser:
public static class ListSerialiser implements JsonSerializer<List<Member>> {
#Override
public JsonElement serialize(List<Member> src, Type type, JsonSerializationContext context) {
JsonObject object = new JsonObject();
List<String> memberId = new ArrayList<>(src.size());
for (Member member : src) {
memberId.add("" + Member.getId());
}
String memberIdAsString = TextUtils.join(",", memberId);
object.addProperty("[%s]", memberIdAsString);
return object;
}
}
Although my implementation got me what I wanted, just out of curiosity, I was wondering if there's a way to serialise without having to use Text Utils or string formatters to achieve this outcome: {"id":"21,22,23"}
There are a lot of ways to join strings, you can see most of them here
My favourite is:
String memberIdAsString = memberId.stream().collect(Collectors.joining(","));
I have converted some info to Json format using Jackson in Java. Below is the output I get
[{"lat":45.9,"lon":10.9,"title":"Title A1","html":"<h3>Content A1</h3>","icon":"http://maps.google.com/mapfiles/markerA.png"},{"lat":44.8,"lon":1.7,"title":"Title B1","html":"<h3>Content B1</h3>","icon":"http://maps.google.com/mapfiles/markerB.png","show_infowindow":false},{"lat":51.5,"lon":-1.1,"title":"Title C1","html":"<h3>Content C1</h3><p>Lorem Ipsum..</p>","zoom":8,"icon":"http://maps.google.com/mapfiles/markerC.png"}]
My question is how can I get it in the below format, basically adding the Json to a root node which called locations
{"locations":[{"lat":45.9,"lon":10.9,"title":"Title A1","html":"<h3>Content A1</h3>","icon":"http://maps.google.com/mapfiles/markerA.png"},{"lat":44.8,"lon":1.7,"title":"Title B1","html":"<h3>Content B1</h3>","icon":"http://maps.google.com/mapfiles/markerB.png","show_infowindow":false},{"lat":51.5,"lon":-1.1,"title":"Title C1","html":"<h3>Content C1</h3><p>Lorem Ipsum..</p>","zoom":8,"icon":"http://maps.google.com/mapfiles/markerC.png"}]}
You may wrap the array into a JSONObject like so
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> map = new HashMap<String, Object>();
String json = jsonArray.toString();
map.put("locations", json);
json = mapper.writeValueAsString(map);
you can achieve this by following changes.
Let's Assume, your JSON will be created based upon Bean.java class likewise,
[{"lat":45.9,"lon":10.9,"title":"Title A1","html":"<h3>Content A1</h3>","icon":"http://maps.google.com/mapfiles/markerA.png"},{"lat":44.8,"lon":1.7,"title":"Title B1","html":"<h3>Content B1</h3>","icon":"http://maps.google.com/mapfiles/markerB.png","show_infowindow":false},{"lat":51.5,"lon":-1.1,"title":"Title C1","html":"<h3>Content C1</h3><p>Lorem Ipsum..</p>","zoom":8,"icon":"http://maps.google.com/mapfiles/markerC.png"}]
Now, As per your new requirement, you want something likewise,
{"locations":[{"lat":45.9,"lon":10.9,"title":"Title A1","html":"<h3>Content A1</h3>","icon":"http://maps.google.com/mapfiles/markerA.png"},{"lat":44.8,"lon":1.7,"title":"Title B1","html":"<h3>Content B1</h3>","icon":"http://maps.google.com/mapfiles/markerB.png","show_infowindow":false},{"lat":51.5,"lon":-1.1,"title":"Title C1","html":"<h3>Content C1</h3><p>Lorem Ipsum..</p>","zoom":8,"icon":"http://maps.google.com/mapfiles/markerC.png"}]}
So, in this case you need to create one more class, let's say it's SuperBean.java then it should be likewise,
public class SuperBean {
private Bean [] locations;
public Bean[] getBean() {
return locations;
}
public void setBean(Bean[] locations) {
this.locations = locations;
}
}
So, your JSON will be created likewise,
{"locations":[......]} // as per your requirement.
{
"localeCode": "",
"map": {
"DynamicName1": [],
"DynamicName2": [
{
"date": "2016-05-15T00:00:00",
"seqId": 1,
"status": 10
},
{
"date": "2016-05-16T00:00:00",
"seqId": 83,
"status": 10
}
],
"DynamicName3": [],
"DynamicName4": []
},
"respCode": 100,
"respMsg": "success",
"status": 1
}
How to correctly map this kind of json. If you can see that, Dynamic is a dynamic name. So far I have done this :
public class MapModel {
public MapObject map;
public static class MapObject{
public java.util.Map<String, Student> queryStudent;
public static class Student{
public String date;
public String seqId;
public String status;
}
}
}
But when run the app. I'm getting NullPointerException. Can somebody help me?
You're getting the NullPointerException accessing queryStudent of your MapObject inside your MapModel since it's not correctly filled when you're trying to deserialize your Json.
So to solve your problem look at Gson documentation where you can see:
You can serialize the collection with Gson without doing anything
specific: toJson(collection) would write out the desired output.
However, deserialization with fromJson(json, Collection.class) will
not work since Gson has no way of knowing how to map the input to the
types. Gson requires that you provide a genericised version of
collection type in fromJson(). So, you have three options:
Use Gson's parser API (low-level streaming parser or the DOM parser
JsonParser) to parse the array elements and then use Gson.fromJson()
on each of the array elements.This is the preferred approach. Here is
an example that demonstrates how to do this.
Register a type adapter for Collection.class that looks at each of the
array members and maps them to appropriate objects. The disadvantage
of this approach is that it will screw up deserialization of other
collection types in Gson.
Register a type adapter for MyCollectionMemberType and use fromJson()
with Collection.
Since your MapObject containts a java.util.Map but your class itself it's not generic, I think that a good approach for your case is create a Deserializer.
Before this try to clean up your class definition, to provide constructors to make the deserializer easy to build. Your POJO classes could be:
Student class
public class Student{
public String date;
public String seqId;
public String status;
public Student(String date, String seqId, String status){
this.date = date;
this.seqId = seqId;
this.status = status;
}
}
MapObject class
Note: I change you Map definition, since in your Json seems that could be multiple students for each DynamicName (look at DynamicName2 from your question), so I use Map<String,List<Student>> instead of Map<String,Student>:
public class MapObject{
public Map<String,List<Student>> queryStudent;
public MapObject(Map<String,List<Student>> value){
this.queryStudent = value;
}
}
MapModel class
public class MapModel {
public MapObject map;
}
Now create a Deserializer for your MapObject:
public class MapObjectDeserializer implements JsonDeserializer<MapObject> {
public MapObject deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
Map<String,List<Student>> queryStudents = new HashMap<String,List<Student>>();
// for each DynamicElement...
for (Map.Entry<String,JsonElement> entry : json.getAsJsonObject().entrySet()) {
List<Student> students = new ArrayList<Student>();
// each dynamicElement has an Array so convert and add an student
// for each array entry
for(JsonElement elem : entry.getValue().getAsJsonArray()){
students.add(new Gson().fromJson(elem,Student.class));
}
// put the dinamic name and student on the map
queryStudents.put(entry.getKey(),students);
}
// finally create the mapObject
return new MapObject(queryStudents);
}
}
Finally register the Deserializer and parse your Json:
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(MapObject.class, new MapObjectDeserializer());
Gson gson = builder.create();
MapModel object = gson.fromJson(YourJson,MapModel.class);
DISCLAIMER: For fast prototyping I test this using groovy, I try to keep the Java syntax but I can forget something, anyway I think that this can put you on the right direction.
Hope it helps,
I have a model class method which returns a list of objects which contains all the registered user details. I want to fetch the list resturned by all() method and convert the data into JSON object and pass it to the view like a string. How can I do this conversion of this array list to JSON object?
I was unable to do this by below:
ObjectMapper mapper = new ObjectMapper();
JSONObject json = new JSONObject();
JsonNodeFactory jsonnode = JsonNodeFactory.instance;
ObjectNode result = new ObjectNode(jsonnode);
for (int i = 0; i < list.size(); i++) {
json.put(list.get(i).fname, list.get(i));
System.out.println(json.get("fname"));
}
#Entity
class Mydata extends Model {
#Id
public Long Id;
public String fname;
public String lname;
public String city;
public String state;
/****************** READ/select OPERATION *****************/
public static Finder < Long, Mydata > finder = new Finder(Long.class, Mydata.class);
public static List < Mydata > all() {
return finder.all();
}
public static void createuser(Mydata user) {
user.save();
}
}
To convert ArrayList to Json, just download Open Source json utility from:
http://json.org/java/ or Jar file from here
And just do:
JSONArray jsonAraay = new JSONArray(your_array_list);
That's it
Note: You should have setter/getter in your POJO/MODEL class to convert arraylist to json
Don't bother with org.json, use Jackson all the way:
// list is a List<MyData>
final ObjectMapper mapper = new ObjectMapper();
final Map<String, MyData> map = new HashMap<>();
for (final MyData data: list)
map.put(data.fname, data);
final JsonNode json = mapper.valueToTree(map);
You could use all sorts of third party libraries like others here have suggested, or just use Play's own simplified methods for this (found in play.libs.Json) which works with Jackson objects, but it is integrated into the framework and requires a lot less code to use, for example:
JsonNode myJsonNode = Json.toJson(MyListObject); which converts the List to a JsonNode object, then use something like String jsonResult = Json.stringify(myJsonNode); to convert it into a string representation.
If you are using the JSON in a template, don't forget to wrap it in something like #Html(myJsonString) so it will not escape anything. Otherwise, if you are just outputting the pure JSON to the browser, a simple return ok(jsonResult); will work as Play will automatically set the content type.
Reference link: http://www.playframework.com/documentation/api/2.0/java/play/libs/Json.html
have you looked at this:
http://www.json.org/javadoc/org/json/JSONObject.html#valueToString(java.lang.Object)
JSONObject.valueToString(<<your list of custom object>> OR <<objects>> OR <<map>>)
works just fine...there are some other methods on that lib, if you are interested....
I would like to fill object fields with values from Json in object constructor.
public AbstractObject(String jsonSerializedObject) {
Gson gson = new Gson();
// Fill object values from json in *current* object
}
Is this possible?
Gson doesn't support "populating existing object" (yet). See issue 431 here.
http://code.google.com/p/google-gson/issues/detail?id=431&q=existing
You can use an InstanceCreator to supply the object that you want to populate.
final Foo existing;
InstanceCreator<Foo> creator = new InstanceCreator<Foo>() {
public Foo createInstance(Type type) { return existing; }
}
Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class, creator).create();
Foo value = gson.fromJson(jsonString, Foo.class);
// value should be same as existing
http://www.javacreed.com/gson-typeadapter-example/
Override the constructor with the object you want to fill, and then update the object in the read(jsonReader: JsonReader) method.
Example in Kotlin:
class TypeAdapterGen : TypeAdapter<Gen> {
var mGen: Gen
constructor(gen: Gen) : super(){
mGen = gen
}
}