Gson — Mapping of Maps

Datetime:2016-08-23 03:11:06          Topic:          Share

After publishing multiple blog posts on how to work with a variety of data types, we'll explore working with Java Maps in this one. You'll learn how to (de)serialize Java Maps using the Gson library.

Of course, this is not the only post in our Gson series. If you're interested in other topics, check out our series outline:

Gson Series Overview

  1. Getting Started with Java-JSON Serialization & Deserialization
  2. Mapping of Nested Objects
  3. Mapping of Arrays and Lists of Objects
  4. Mapping of Maps
  5. Mapping of Sets
  6. Mapping of Null Values
  7. Gson Model Annotations — How to Ignore Fields with @Expose
  8. Gson Model Annotations — How to Change the Naming of Fields with @SerializedName
  9. Gson Builder — Basics & Naming Policies
  10. Gson Builder — Force Serialization of null Values
  11. Gson Builder — Exclusion Strategies
  12. Gson Builder — Relax Gson with Lenient
  13. Gson Builder — Special Values of Floats & Doubles
  14. Gson Builder — Model Versioning
  15. Gson Builder — Formatting of Dates & Custom Date/Time Mapping
  16. Gson Builder — Pretty Printing
  17. Gson Builder — HTML Escaping

Serialization of Java Maps

Java maps are a very flexible data type and can be used for an assortment of scenarios. It allows us developers to materialize a lot of real-world situations in the Java programming language. Since Java maps are used in such a variety we probably won't cover your exact use case, but the approach applies for all of them.

Let's start with the scenario that your app has a list of employee names. You were asked to implement a view to show all employees which start with a specific first letter. For example, the user can select the letter A and your application would return the three matching employees Andreas , Aden and Arnold . The first iteration was just a list with all names, but the performance wasn't good enough. Thus, the implementation was switched to a HashMap where the key is the first letter (i.e. A ) and the value is a list of names.

If we create our HashMap our Java code would look like this:

HashMap<String, List<String>> employees = new HashMap<>();  
employees.put("A", Arrays.asList("Andreas", "Arnold", "Aden"));  
employees.put("C", Arrays.asList("Christian", "Carter"));  
employees.put("M", Arrays.asList("Marcus", "Mary"));  

The serialization of maps is the same as with any other type. You can just throw it at Gson and it'll do the correct thing:

Gson gson = new Gson();  
String employeeJson = gson.toJson(employees);  

This would result in this JSON:

{
  "M": [
    "Marcus",
    "Mary"
  ],
  "C": [
    "Christian",
    "Carter"
  ],
  "A": [
    "Andreas",
    "Arnold",
    "Aden"
  ]
}

The keys ( A , C and M ) each have a list of names, which is exactly what we wanted to describe.

Deserialization of Java Maps

If you look at the result JSON of the previous section, or the JSON below, you'll ask yourself: how can you spot the difference between a set and multiple objects? The simple answer is: you can't. This is one of the few instances where the JSON data representation is ambiguous. Let's look at the following example:

{
  "1$": {
    "amount": 1,
    "currency": "Dollar"
  },
  "2$": {
    "amount": 2,
    "currency": "Dollar"
  },
  "3€": {
    "amount": 3,
    "currency": "Euro"
  }
}

This is the JSON, where the reader could assume that there are three objects with the name 1$ , 2$ and 3€ . Each of these objects has some values. But on the other hand it can also be a simple Map where the 1$ , 2$ and 3€ are keys.

There is no fool-proof way of evaluate what data type a JSON is. Some pointers to assist you are:

  • First and most important of all: context knowledge! If you've documentation or know what the objects are describing you should be able to interpret if there are separate objects or a map of data.
  • Is the data type of the value consistent? Then it hints toward a map.
  • Are the object names/keys dynamic and of a wide range? This also hints toward a map.

We've already shown you in aprevious blog post how to map regular objects, so in this blog post we'll assume the JSON is a map of data. How can we map the JSON shown above to Java objects?

We can use the same TypeToken approach we've shown you in theList of Objects blog post. You create an appropriate Type by creating a new TypeToken with our expected data type:

public class AmountWithCurrency {  
    String currency;
    int amount;
}

String dollarJson = "{ '1$': { 'amount': 1, 'currency': 'Dollar'}, '2$': { 'amount': 2, 'currency': 'Dollar'}, '3€': { 'amount': 3, 'currency': 'Euro'} }";

Gson gson = new Gson();

Type amountCurrencyType =  
    new TypeToken<HashMap<String, AmountWithCurrency>>(){}.getType();

HashMap<String, AmountWithCurrency> amountCurrency =  
    gson.fromJson(dollarJson, amountCurrencyType);

The amountCurrency variable actually holds the full set with the correct keys and values:

Nested Maps

Map data structures don't have to be the root element of the model/JSON. It can be just a property of an object. You'd (de)serialize it the same way like you've to with lists. We already published a guide for nested behaviorhere.

Outlook

In this blog post you've seen how you can serialize and deserialize Java maps from and to JSON. You've learned the potential obstacles and how to overcome them. In the next blog post we'll look at the very similar Java data type Sets . Stay tuned!

If you've feedback or a question, let us know in the comments or on twitter @futurestud_io .

Make it rock & enjoy coding!