7

Let's assume we have the following two Java Classes (omitting the other class members):

class Book {
    private String name;
    private String[] tags;
    private int price;
    private Author author;
}

class Author {
    private String name;
}

Furthermore, assume we have the following json object:

{"Book": {
    "name": "Bible",
    "price": 20,
    "tags": ["God", "Religion"],
    "writer": {
        "name": "Jesus"
    }
}

I am trying to find the best way to convert a Java Book instance to json and back using gson. To make the example more interesting, note that in json, I want to use "writer" instead of "Author". Can you please help? Ideally, I would like to see a complete implementation.

happyhuman
  • 1,541
  • 1
  • 16
  • 30
  • 1
    Can we see some of your efforts in this regard? – Ali Gajani May 28 '14 at 18:53
  • 1
    Ideally, we wouldn't like to do your homework. If you google around a bit, you will find tonnes of example implementations of how to use gson. – anu May 28 '14 at 18:57
  • Validate your JSON String here [JSONLint - The JSON Validator](http://jsonlint.com/) – Braj May 28 '14 at 19:22
  • I post here only if my searching for an answer fails. I am already familiar with gson and how to convert an object to/from json manually which becomes a cumbersome task for big Java objects. I am mainly seeking to automate the effort by configuring gson to do it automatically (specially for the fromJson). The example I posted above is artificial, but it has everything I need to learn in order to do my own coding. My main question is about configuring gson to know that the value of "writer" key should be converted to an instance of Author class. That I don't know how to do. – happyhuman May 28 '14 at 23:21

2 Answers2

7

Try with GsonBuilder#setPrettyPrinting() that configures Gson to output Json that fits in a page for pretty printing. This option only affects Json serialization.

Read more about Gson that is typically used by first constructing a Gson instance and then invoking below method on it.

  • toJson(Object) that serializes the specified object into its equivalent Json representation.

  • fromJson(String, Class) that deserializes the specified Json into an object of the specified class.


BookDetails Object to JSON String

Sample code:

Book book = new Book();
book.setName("Bible");
book.setTags(new String[] { "God", "Religion" });
book.setPrice(20);
Author author = new Author();
author.setName("Jesus");
book.setWriter(author);

BookDetails bookDetails = new BookDetails();
bookDetails.setBook(book);

String jsonString = new Gson().toJson(bookDetails);
// JOSN with pretty printing
// String jsonString = new GsonBuilder().setPrettyPrinting().create().toJson(bookDetails);
System.out.println(jsonString);

output:

{"Book":{"name":"Bible","tags":["God","Religion"],"price":20,"writer":{"name":"Jesus"}}}

JSON String to BookDetails Object

BookDetails newBookDetails = new Gson().fromJson(jsonString, BookDetails.class);

Here is the classes

class BookDetails {
    private Book Book;
    // getter & setter
}

class Book {
    private String name;
    private String[] tags;
    private int price;
    // Variable name should be writer instead of author as mapped to JSON string
    private Author writer; 
    // getter & setter
}

class Author {
    private String name;
    // getter & setter
}
Braj
  • 46,415
  • 5
  • 60
  • 76
  • Thanks. Just two quick questions: Why did you need to implement BookDetails? and, how do you tell gson to map the value of "writer" in the json object to an instance of Author class and vice versa? – happyhuman May 28 '14 at 22:55
  • 1
    All the POJO classes should have same replica as shown in JSON string. The name of variables must be case sensitive. Read [Why does GSON use fields and not getters/setters?](http://stackoverflow.com/questions/6203487/why-does-gson-use-fields-and-not-getters-setters). Here you have created a variable `writer` that is of type `Author`, Gson reads from field and assign the value of `name` to `Author`'s `name` variable. Here `BookDetails` is used in the same way to make a `variable` that represents initial `Book` value of the JSON string and mapped in the same way as did for `Author`. – Braj May 29 '14 at 03:23
  • 1
    Let me summarize it - `Gson` uses **fields names** to map the JSON string to object and vice-versa. – Braj May 29 '14 at 03:25
  • 1
    use `Author writer;` instead of `Author author;` to map `writer` from the JSON string. – Braj May 29 '14 at 03:27
  • Don't forget to close the thread if the issue is resolved. You have already asked 7 question but none of them is closed? – Braj May 29 '14 at 20:04
6

Thanks for all the answers. I was able to figure it out and implement it using some custom serializer and deserializer. Here is my own solution:

public class JsonTranslator {
    private static Gson gson = null;

    public void test(Book book1) {
        JsonElement je = gson.toJson(book1);  // convert book1 to json
        Book book2 = gson.fromJson(je, Book.class); // convert json to book2
        // book1 and book2 should be equivalent
    }

    public JsonTranslator() {

        GsonBuilder builder = new GsonBuilder();
        builder.registerTypeAdapter(Book.class, new BookTrnaslator());
        builder.registerTypeAdapter(Author.class, new AuthorTrnaslator());
        builder.setPrettyPrinting();
        gson = builder.create();
    }


    private class BookTrnaslator implements JsonDeserializer<Book>, JsonSerializer<Book> {
        public Card deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            JsonObject jobj = json.getAsJsonObject();
            Book book = new Book();
            book.setName(jobj.get("name").getAsString());
            book.setTags(jobj.get("tags").getAsJsonArray()); //Assuming setTags(JsonArray ja) exists
            book.setName(jobj.get("price").getAsInt());
            book.setAuthor(gson.fromJson(jobj.get("writer"), Author.class));
            return book;
        }

       public JsonElement serialize(Book src, Type typeOfSrc, JsonSerializationContext context) {
            JsonObject jobj = new JsonObject();
            jobj.addProperty("name", src.getName());
            jobj.add("tags", src.getTagsAsJsonArray());
            jobj.addProperty("price", src.getPrice());
            jobj.add("writer", gson.toJson(src.getAuthor()));
            return jobj;
       }
    }

    private class AuthorTrnaslator implements JsonDeserializer<Author>, JsonSerializer<Author> {
        public Card deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            JsonObject jobj = json.getAsJsonObject();
            Author author = new Author();
            author.setName(jobj.get("name").getAsString());
            return author;
        }

       public JsonElement serialize(Author src, Type typeOfSrc, JsonSerializationContext context) {
            JsonObject jobj = new JsonObject();
            jobj.addProperty("name", src.getName());
            return jobj;
       }
    }
}
happyhuman
  • 1,541
  • 1
  • 16
  • 30