-
Notifications
You must be signed in to change notification settings - Fork 16
Json
<wiki:toc max_depth="3" />
JSON (de)serialization works by selecting a "path" expression. In the simplest case the path is just the key of the JSON data. For more complex cases, you can also use a JSONPath expression. If necessary, the selected data is converted to the type of the annotated property.
Let's assume you want to map the following JSON data
{
"isbn": "978-0345417954",
"pages": 432,
"title": "The Hotel New Hampshire",
"author": {
"firstname": "John",
"surname": "Irving",
},
"reviews": [
"A hectic gaudy saga with the verve of a Marx Brothers movie.",
"Rejoice! John Irving has written another book according to your world.",
"Spellbinding, intensely human, a high-wire act of dazzling virtuosity."
]
}
Therefore you have the following POJOs in your GWT client
public class Book
{
String isbn;
int pages;
String title;
Author author;
List<String> reviews;
}
public class Author
{
String firstname;
String surname;
}
To map the JSON to your classes, all you have to do is to define an interface of type !JsonReader<T>
:
public class Book
{
interface BookReader extends JsonReader<Book> {}
public static final BookReader READER = GWT.create(BookReader.class);
String isbn;
int pages;
String title;
Author author;
List<String> reviews;
}
public class Author
{
interface AuthorReader extends JsonReader<Author> {}
public static final AuthorReader READER = GWT.create(AuthorReader.class);
String firstname;
String surname;
}
Now you can map the JSON by calling
String jsonString = ...; // the above JSON data
Book book = Book.READER.read(jsonString);
Please note that Piriti does not use javascript eval()
but the browsers native JSON parser (or a javascript emulation if no native parser is available). Hence the JSON data must confirm to the syntax described at JSON.org. Especially the keys must be enclosed in ". So instead of
{ readonly: true, name: "Foo", createdAt: "08.01.2010", count: 20 }
you have to use
{ "readonly": true, "name": "Foo", "createdAt": "08.01.2010", "count": 20 }
POJOs can be serialized to JSON by using the same annotations which are used for parsing. To generate JSON from existings POJO instances you have to define a JsonWriter<T>
interface.
public class Book
{
public interface BookReader extends JsonReader<Book> {}
public static final BookReader READER = GWT.create(BookReader.class);
public interface BookWriter extends JsonWriter<Book> {}
public static final BookWriter WRITER = GWT.create(BookWriter.class);
String isbn;
int pages;
String title;
Author author;
List<String> reviews;
}
public class Author
{
public interface AuthorReader extends JsonReader<Author> {}
public static final AuthorReader READER = GWT.create(AuthorReader.class);
public interface AuthorWriter extends JsonWriter<Author> {}
public static final AuthorWriter WRITER = GWT.create(AuthorWriter.class);
String firstname;
String surname;
}
A typical scenario would be to parse the JSON received from the server, make some modifications and send back the modified JSON:
String json = ...; // received from the server
Book book = Book.READER.read(json);
book.title += " 2nd edition";
json = Book.WRITER.toJson(book);
// do some REST request
When POJOs are serialized null values will be processed:
Book book = new Book();
book.isbn = null;
book.pages = 0;
book.title = "";
book.author = null;
book.reviews = new ArrayList<String>();
String json = Book.WRITER.toJson(book);
will result in
{
"isbn": null,
"pages": 0,
"title": "",
"author": null,
"reviews": []
}
By default Piriti uses the fields name as key to the JSON data. But sometimes there's no 1:1 correlation between the field and the JSON key. Say you want to create flat model objects from nested JSON structures:
public class Person
{
String name;
String street;
String city;
}
{
"name": "Hans Dampf",
"address": {
"street": "Hirbeldirbel 1",
"city": "Equalizerhofen"
}
}
To map street and city you have to use JSONPath expressions (@ references the current JSONObject):
public class Person
{
// Reader definition omitted
String name;
@Path("@.address.street") String street;
@Path("@.address.city") String city;
}
JSONPath is based on the javascript library from Stefan Gössner. See the following links for more examples and the full syntax:
When generating the mapping code, Piriti looks at the value of the @Path annotation. In case it detects any of the following characters, the value is interpreted as JSONPath: '$', '@', '.', '[', ']', '*', '#', ',', ':', '?', '(', ')'
Please note that fields with JSONPath expressions cannot be serialized. Those fields are skipped by the generated writers:
public class Person
{
public interface PersonWriter extends JsonWriter<Person> {}
public static final PersonWriter WRITER = GWT.create(PersonWriter.class);
String name;
@Path("@.address.street") String street;
@Path("@.address.city") String city;
}
...
Person p = new Person();
p.name = "Hans Dampf";
p.street = "Hirbeldirbel 1";
p.city = "Equalizerhofen";
String json = Person.WRITER.toJson(p);
will result in
{
"name": "Hans Dampf"
}