Generate JSON with collection represented with indexed items - java

Is there some library that can generate JSON object in which collection is represented as set of numbered items?
When using for example GSON library and have class like this:
`class Bus {
List<Pasenger> passengers;
public Bus(List<Pasenger> passengers) {
this.passengers = passengers;
}
}`
GSON generates JSON like this:
`{"bus":{
"passengers":[
{"name":"John","familiName":"Smith"},
{"name":"Marry","familiName":"James"}
]
}}`
But what I am requested is to generate JSON in which collection is represented with items each of which having its index.
Like this:
`{"bus":{
"passengers[0]":{"name":"John","familiName":"Smith"},
"passengers[1]":{"name":"Marry","familiName":"James"}
}}`
I digged in GSON and FasterXML but could not find support for this functionality.
Does anybody know if there is some library supporting this?
Any help appreciated.

You can create a class that implements JsonSerializer to specify how you want it to be serialized.
And then register it when building your Gson:
Gson gson = new GsonBuilder().registerTypeAdapter(Bus.class, new BusAdapter()).create();
More info: https://github.com/google/gson/blob/master/UserGuide.md#TOC-Writing-a-Serializer

I think it is possible for you to create Map instead of List (if you don't want to write custom serializer and deserializer). And constructor for Bus will be like:
private Map<String, Pasenger> bus = new HashMap<>();
public Bus(List<Pasenger> passengers) {
for (int i = 0; i < passengers.size(); i++){
bus.put("passengers["+i+"]", passengers.get(i));
}
}
For simple pasenger only with name it looks like
{"bus":
{
"passengers[0]":{"name":"first"},
"passengers[1]":{"name":"second"}
}
}

Related

Java - Gson not working with Object defined on the fly

I would like not to define an extra type just to make the json conversion. I am using a library that needs an object as an input and then performs http operations with this data, so I cannot use a hard coded json string as input.
private static final Gson GSON = new Gson();
public static void main(String[] args) {
System.out.println(GSON.toJson(new Object() {
private String email_address = "me#mail.eu";
public String getEmail_address() {return "me#mail.eu"; }
public void setEmail_address(String mail) {email_address = mail; }
}));
}
I tried to remove getter and setter or leave the getter and remove the field but it doesn't work. Anybody knows how to fix this?
Libraries for Json serialization/deseralization like Gson, count on the fact that you have defined your custom object on which you will map the json string. This is because they use reflection on the class to map the fields with the corresponding keys in the json. Without it, it is difficult that they can achieve anything(usable).
Why not define an extra type ? We are not in the 1980s. I would personnally use a DTO. What is Data Transfer Object?
But maybe the answer to you question reside here : Java - Does Google's GSON use constructors?

Convert Java List to Javascript Array

I have the following java code in my Android application and wanted a way to convert the Java list to an array that can be used in javascript:
Java:
public void onCompleted(List<GraphUser> users, Response response) {
for(int i = 0; i < users.size(); i++)
{
//add to an array object that can be used in Javascript
webView.loadUrl("javascript:fetchFriends(arrObj)");
}
}
Javascript:
//this is how I want to be able to use the object in Javascript
function parseFriends(usersObjectFromJava){
var users = [];
for (var i = 0; i < usersObjectFromJava.length; i++) {
var u = {
Id: usersObjectFromJava[i].id + "",
UserName: usersObjectFromJava[i].username,
FirstName: usersObjectFromJava[i].first_name,
LastName: usersObjectFromJava[i].last_name,
};
users[i] = u;
}
}
Could some help me with the Java code to create the usersObjectFromJava so that it can be used in javascript?
Use GSON
to convert java objects to JSON string, you can do it by
Gson gson = new Gson();
TestObject o1 = new TestObject("value1", 1);
TestObject o2 = new TestObject("value2", 2);
TestObject o3 = new TestObject("value3", 3);
List<TestObject> list = new ArrayList<TestObject>();
list.add(o1);
list.add(o2);
list.add(o3);
gson.toJson(list) will give you
[{"prop1":"value1","prop2":2},{"prop1":"value2","prop2":2},{"prop1":"value3","prop2":3}]
Now you can use JSON.parse(), to deserialize from JSON to Javascript Object.
I would assume doing this:
Java:
public void onCompleted(List<GraphUser> users, Response response) {
JSONArray arr = new JSONArray();
JSONObject tmp;
try {
for(int i = 0; i < users.size(); i++) {
tmp = new JSONObject();
tmp.put("Id",users.get(i).id); //some public getters inside GraphUser?
tmp.put("Username",users.get(i).username);
tmp.put("FirstName",users.get(i).first_name);
tmp.put("LastName",users.get(i).last_name);
arr.add(tmp);
}
webView.loadUrl("javascript:fetchFriends("+arr.toString()+")");
} catch(JSONException e){
//error handling
}
}
JavaScript:
function fetchFriends(usersObjectFromJava){
var users = usersObjectFromJava;
}
You will have to change the Java-Code a bit (i.e. using public getters or add more/less information to the JSONObjects.
JSON is included in Android by default, so no external libraries are necessary.
I hope i understood your problem.
Small thing i came across: you where using fetchFriends in Java but its called parseFriends in Javascript, I renamed them to fetchFriends
You can use Gson Library.
Gson gson = new GsonBuilder().create();
JsonArray jsonArray = gson.toJsonTree(your_list, TypeClass.class).getAsJsonArray();
http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/Gson.html
Use Jackson.
You'll need to add an " #JsonProperty" annotation to every property of your POJOs you want to pass, then do something like this:
String respStr = "";
for(Object whatever: MyList)
{
JSONObject dato = new JSONObject();
dato.put("FirstField", whatever.SomeData());
dato.put("SecondField", whatever.SomeData2());
StringEntity entity = new StringEntity(dato.toString());
post.setEntity(entity);
webView.loadUrl("javascript:fetchFriends("+entity+")");
}
I am not sure why no answer mentioned about jaxb. I am just thinking jaxb would be a good fit for this type of problems...
For a sample style of annotated jaxb class, please find this.
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class ResponseAsList {
private List < Object > list = new ArrayList < Object > ();
public ResponseAsList() {
// private default constructor for JAXB
}
public List < Object > getList() {
return list;
}
public void setList(List < Object > list) {
this.list = list;
}
}
You will stuff your data in these lists and you will marshal either in xml or a json. After you get a json to the client, you can do a var myArray = JSON.parse(response);...
Although I typically advocate using something like GSON or Jackson to do JSON conversions for you, its pretty easy to roll your own if you're in a limited environment (like Android) and don't want to bundle a bunch of dependencies.
public class JsonHelper {
public static String convertToJSON(List<GraphUser> users) {
StringBuilder sb = new StringBuilder();
for (GraphUser user : users) {
sb.append(convertToJSON(user));
}
return sb.toString();
}
public static String convertToJSON(GraphUser user) {
return new StringBuilder()
.append("{")
.append("\"id\":").append(user.getId()).append(",")
.append("\"admin\":").append(user.isAdmin() ? "true" : "false").append(",")
.append("\"name\":\"").append(user.getName()).append("\",")
.append("\"email\":\"").append(user.getEmail()).append("\"")
.append("}")
.toString();
}
}
You could obviously make a toJSON() method on GraphUser to put the logic if you prefer. Or use an injectable json helper library instead of static methods (I would). Or any number of other abstractions. Many developers prefer to separate representation of model objects into their own object, myself included. Personally, I might model it something like this if I wanted to avoid dependencies:
interface Marshaller<F,T> with methods T marshall(F obj) and F unmarshall(T obj)
interface JsonMarshaller<F> extends Marshaller<String>
class GraphUserMarshaller implements JsonMarshaller<GraphUser>
class GraphUserCollectionMarshaller implements JsonMarshaller<Collection<GraphUser>> which could do type-checking or use the visitor pattern or something to determine the best way to represent this type of collection of objects.
Along the way, I'm sure you'll find some repeated code to extract to super- or composite- classes, particularly once you start modeling collection marshallers this way. Although this can get to be pretty verbose (and tedious), it works particularly well in resource-constrained environments where you want to limit the number of libraries on which you depend.
You can use the Google Gson library (http://code.google.com/p/google-gson/) to convert the Java List Object to JSON. Ensure that the right fields are set like ID, UserName, FirstName, etc and on the java script side that same code would work.
Its just an example, First add javascript interface. It will be a bridge between javascript and java code.
webView.addJavascriptInterface(new JSInterface(), "interface");
In javascript you can add like this,
"window.interface.setPageCount(pageCount1);"
The interface is a keyword in common between java and javascript. create a class JSInterace and define a method setPageCount(int a). The script will return a value, and you can use that value in your java method

Mapping a JSONObject to a List with Flexjson in Java / Android

I'm currently trying to use Flexjson to deserialize a JSON String and map it to the Object model of my
Android App. The application is a kind of library with several vendors that can have some catalogs with more catalogs
and documents in them. The json is fetched from a web service I have no influence on and looks something like this:
{
"library":{
"vendor":[
{
"id":146,
"title":"Vendor1",
"catalog":[
{
"id":847,
"document":[
{
"id":1628,
"title":"Document",
...
},
{
...
}
],
"title":"Catalog ",
},
{
...
}
]
},
{
...
}
]
}
}
So each vendor, catalog, document is represented by a JSONObject and all child catalogues and documents are within a JSONArray.
So far everything works fine with Flexjson and the following deserialization code:
LibraryResponse response = new JSONDeserializer<LibraryResponse>()
.use(Timestamp.class, new TimestampObjectFactory())
.deserialize(getLocalLibrary(), LibraryResponse.class);
return response.library;
I do have a Library object that has a List<Vendor>. Each vendor has a List<Catalog> and a List<Document>.
But unfortunately, the web service straps the JSONArrays to simple JSONObjects if a catalog contains only a single document
or a catalog contains just one catalog. So the json in that case looks like this:
"document":
{
"id":1628,
"title":"Document",
...
}
Now Flexjson doesn't know how to deserialize and I end up with a library.vendorX.getDocument() being a List<HashMap> instead of a List<Document>.
One idea is to tell Flexjson explicitly how to handle such cases, but I have no idea where to start with this. Another way could be to parse the initial json manually and replace such JSONObjects with the appropriate JSONArray. But I think that way is not really nice to go, as the library can be pretty deep.
I hope you can provide some guidance here.
Yikes this is some gnarly json mapping going on. What backend coder did that?! #NotHelping.
Well from looking at the code, Flexjson is coded to handle this out of the box. But it looks like it's not passing the typing information down to the bind so it doesn't know what type it's binding into so it just returns a Map. That's a bug that should probably be fixed. Good news is there is a work around.
Anyway, the simplest thing I can think of is to install an ObjectFactory on that list. Then you can check and see if you get a Map or a List when the stream is deserialized. Then you can wrap it in a List and send it on to the appropriate decoder. Something like:
LibraryResponse response = new JSONDeserializer<LibraryResponse>()
.use(Timestamp.class, new TimestampObjectFactory())
.use("library.vendor.values.catalog.values.document", new ListDocumentFactory() )
.deserialize(getLocalLibrary(), LibraryResponse.class);
Then
public class ListDocumentFactory implements ObjectFactory {
public Object instantiate(ObjectBinder context, Object value, Type targetType, Class targetClass) {
if( value instanceof Collection ) {
return context.bindIntoCollection((Collection)value, new ArrayList(), targetType);
} else {
List collection = new ArrayList();
if( targetType instanceof ParameterizedType ) {
ParameterizedType ptype = (ParameterizedType) targetType;
collection.add( context.bind(value, ptype.getActualTypeArguments()[0]) );
} else {
collection.add( context.bind( value ) );
return collection;
}
}
}
}
I think that's roughly what would fix that bug, but should also fix your problem.

Jackson ObjectMapper with arbitrary JSON keys

I'm using Jackson 1.9.5 in an Android project to parse JSON files.
So far I haven't had any problems, and can parse files fine using the following code:
AssetManager mgr = getAssets();
ObjectMapper mapper = new ObjectMapper();
try {
InputStream ifp = mgr.open("detail_schema.json");
schema = mapper.readValue(ifp, DetailSchema.class);
} catch (IOException e) {
e.printStackTrace();
}
Where the DetailSchema class consists of a mix of primitive types and classes. I'm now running into a problem where I want to parse some JSON like the following:
"fields": {
"Suburb": "Paddington",
"State": "NSW",
"Post Code": "2074",
"Lollipop": "Foo Bar Haz"
}
Where I can't possibly know the map keys before hand (they can be user-defined). As such, I'm not sure what the associated Java class should look like.
Ie, for this example, it could look like:
public class MyClass {
public String Suburb;
public String State;
public String PostCode;
public String Lollipop;
}
But this may not be correct for another instance of the JSON file. Ideally I need some way for Jackson to map values to something like a NameValuePair. I suspect that the automatic object mapping may not be an option in this case - can someone confirm or deny this?
You have two options. Either you can use readTree in ObjectMapper, which returns a JsonNode. Working with a JsonNode is much like working with a tree, so you can get children nodes, read values, et cetera:
InputStream ifp = mgr.open("detail_schema.json");
JsonNode root = mapper.readTree(ifp);
JsonNode fields = root.get("fields");
for (JsonNode children : fields) {
// ...
}
Then you'd need to build your DetailSchema object manually.
Or, you can let Jackson deserialize it as a Map, in which case you'd use your code but where MyClass would be like this:
public class MyClass {
public Map<String, Object> fields;
// getter/setters
}
You can probably type the map values as String as well if you are sure the inputs are text in json. (Actually, I'm not sure what type enforcement Jackson does, maybe it will allow anything anyway...)

Deserialization of generic collections with Gson

I have some difficulties with json deserialization using GSon and I hope somebody can help me.
I want to deserialize the following json snippet:
{
"fieldA": "valueA",
"myCollection": {
"AnotherClass": [
{
"objectAfieldA": "valueB",
"objectAfieldB": "valueC"
},
{
"objectAfieldA": "valueD",
"objectAfieldB": "valueE"
}
]
}
}
the corresponding overall class has following fields:
...
String fieldA;
List<AnotherClass> = new ArrayList<AnotherClass>();
....
Now, my problem is that when I deserialize, using fromJson(jsonSample, resultContainer.class), without the List<T> element, everything is good, but I get a NullPointerException when I include the contained list. I've read about how to deal with collections of generic types and the use of TypeToken, but I can't apply this knowledge when my collection is part of another class…
I really would appreciate any help to solve this.
The solution for deserealizing the unnamed JSON array is quite simple:
List<resultContainer> lres = gson.fromJson(new FileReader("input.json"), new TypeToken<List<resultContainer>>(){}.getType());
When deserializing, you only need to use the TypeToken if the outer-most structure to be deserialized into is a generic collection. This is not the case for the example in the original question. So, use of a TypeToken is unnecessary.
The issue appears to be that the JSON structure does not match the Java structure attempting to be bound to.
The JSON structure defines
an object with two elements
element 1 is a string named "fieldA",
element 2 is an object named "myCollection", which has one element
the one element is an array named "AnotherClass", composed of objects with two elements
element 1 is a string named "objectAfieldA",
element 2 is a string named "objectAfieldB"
So, define a Java data structure to match that, and deserialization will work very simply, without any custom processing necessary. If such a matching Java structure is not provided, then custom deserialization is necessary.
Here is such a working example using the names and types from the original question.
import java.io.FileReader;
import com.google.gson.Gson;
public class Foo
{
public static void main(String[] args) throws Exception
{
Gson gson = new Gson();
resultContainer result = gson.fromJson(new FileReader("input.json"), resultContainer.class);
System.out.println(gson.toJson(result));
}
}
class resultContainer
{
String fieldA;
MyCollectionContainer myCollection;
}
class MyCollectionContainer
{
SomeOtherClass[] AnotherClass;
}
class SomeOtherClass
{
String objectAfieldA;
String objectAfieldB;
}

Categories

Resources