Конвертирайте JSON в карта с помощта на Gson

1. Въведение

В този бърз урок ще научим как да конвертирате JSON низ в карта с помощта на Gson от Google .

Ще видим три различни подхода за постигане на това и ще обсъдим техните плюсове и минуси - с някои практически примери.

2. Предаване на Map.class

По принцип Gson предоставя следния API в своя клас Gson за преобразуване на JSON низ в обект :

public  T fromJson(String json, Class classOfT) throws JsonSyntaxException;

От подписа е много ясно, че вторият параметър е класът на обекта, в който възнамеряваме да анализираме JSON. В нашия случай това трябва да е Map.class :

String jsonString = "{'employee.name':'Bob','employee.salary':10000}"; Gson gson = new Gson(); Map map = gson.fromJson(jsonString, Map.class); Assert.assertEquals(2, map.size()); Assert.assertEquals(Double.class, map.get("employee.salary").getClass());

Този подход ще направи най-доброто предположение относно типа стойност за всяко свойство.

Например числата ще бъдат принудени в Double s, true и false в Boolean и обекти в LinkedTreeMap s.

Ако обаче има дублирани ключове, принудата няма да успее и ще хвърли JsonSyntaxException.

И поради изтриването на типа също няма да можем да конфигурираме това поведение на принуда. Така че, ако трябва да посочим типовете ключ или стойност, тогава ще се нуждаем от различен подход.

3. Използване на TypeToken

За да преодолее проблема с изтриването на типа за родовите типове, Gson има претоварена версия на API :

public  T fromJson(String json, Type typeOfT) throws JsonSyntaxException;

Можем да изградим карта с нейните параметри на типа, като използваме TypeToken на Gson . Класът TypeToken връща екземпляр на ParameterizedTypeImpl, който запазва типа на ключа и стойността дори по време на изпълнение :

String jsonString = "{'Bob' : {'name': 'Bob Willis'}," + "'Jenny' : {'name': 'Jenny McCarthy'}, " + "'Steve' : {'name': 'Steven Waugh'}}"; Gson gson = new Gson(); Type empMapType = new TypeToken() {}.getType(); Map nameEmployeeMap = gson.fromJson(jsonString, empMapType); Assert.assertEquals(3, nameEmployeeMap.size()); Assert.assertEquals(Employee.class, nameEmployeeMap.get("Bob").getClass()); 

Сега, ако конструираме нашия тип Map като Map , тогава парсерът ще продължи по подразбиране, както видяхме в предишния раздел.

Разбира се, това все пак се връща към Gson за принуждаване на примитивни типове. Тези обаче могат да бъдат персонализирани.

4. Използване на персонализиран JsonDeserializer

Когато се нуждаем от фин контрол върху конструкцията на нашия обект Map , можем да внедрим персонализиран десериализатор от тип JsonDeserializer.

За да видим пример, нека приемем, че нашият JSON съдържа името на служителя като ключ и датата на наемането му като негова стойност. Освен това, нека приемем, че форматът на датата е гггг / ММ / дд , което не е стандартен формат за Gson .

Можем да конфигурираме Gson да анализира нашата карта по различен начин, след това, като внедрим JsonDeserializer:

public class StringDateMapDeserializer implements JsonDeserializer { private SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd"); @Override public Map deserialize(JsonElement elem, Type type, JsonDeserializationContext jsonDeserializationContext) { return elem.getAsJsonObject() .entrySet() .stream() .filter(e -> e.getValue().isJsonPrimitive()) .filter(e -> e.getValue().getAsJsonPrimitive().isString()) .collect( Collectors.toMap( Map.Entry::getKey, e -> formatDate(e.getValue()))); } private Date formatDate(Object value) { try { return format(value.getAsString()); } catch (ParseException ex) { throw new JsonParseException(ex); } } } 

Сега трябва да го регистрираме в GsonBuilder спрямо нашата карта от целеви тип > и изградете персонализиран Gson обект.

Когато извикаме API на fromJson за този обект Gson , анализаторът извиква персонализирания десериализатор и връща желания екземпляр на Map :

String jsonString = "{'Bob': '2017-06-01', 'Jennie':'2015-01-03'}"; Type type = new TypeToken(){}.getType(); Gson gson = new GsonBuilder() .registerTypeAdapter(type, new StringDateMapDeserializer()) .create(); Map empJoiningDateMap = gson.fromJson(jsonString, type); Assert.assertEquals(2, empJoiningDateMap.size()); Assert.assertEquals(Date.class, empJoiningDateMap.get("Bob").getClass()); 

Тази тактика е полезна и когато нашата карта може да съдържа разнородни стойности и имаме добра представа колко различни видове ценности могат да бъдат там.

За да научите повече за персонализиран десериализатор в Gson , не се колебайте да разгледате Gson Deserialization Cookbook.

5. Заключение

В тази кратка статия научихме няколко начина за конструиране на карта от форматиран в JSON низ. И ние също обсъдихме правилните случаи на употреба за тези вариации.

Изходният код за примерите е достъпен в GitHub.