Как сериализовать карту карты с помощью GSON? - PullRequest
11 голосов
/ 28 декабря 2010

Я хочу сериализовать мой пример класса ниже в JSON, используя GSON.

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.LinkedHashMap;

public class Example
{
    private LinkedHashMap<String,Object> General;

    private static final String VERSION="Version";
    private static final String RANGE="Range";
    private static final String START_TIME="Start_Time";
    private static final String END_TIME="End_Time";

    public Example() {
        General = new LinkedHashMap<String,Object>();
        General.put(VERSION, "0.1");

        LinkedHashMap<String,String> Range = new LinkedHashMap<String, String>();
        Range.put(START_TIME, "now");
        Range.put(END_TIME, "never");

        General.put(RANGE, Range);
    }

    public String toJSON() {
        Gson gson = new GsonBuilder().serializeNulls().create();
        return gson.toJson(this);
    }
}

Я ожидал получить следующий вывод:

{"General":{"Version":"0.1","Range":{"Start_Time":"now","End_Time":"never"}}}

Но вызов функции toJSON() возвращает

{"General":{"Version":"0.1","Range":{}}}

Похоже, GSON не может сериализовать карту Range внутри карты General. Это ограничение GSON или я здесь что-то не так делаю?

Ответы [ 3 ]

8 голосов
/ 28 декабря 2010

Причина, по которой ответ Нишанта работает, заключается в том, что конструктор Gson по умолчанию разрешает все виды вещей по умолчанию, которые в противном случае вам бы пришлось вручную включить с помощью GsonBuilder.

Из JavaDocs :

Создает объект Gson с конфигурацией по умолчанию.Конфигурация по умолчанию имеет следующие параметры:

  • JSON, сгенерированный методами toJson, находится в компактном представлении.Это означает, что все ненужные пробелы удалены.Вы можете изменить это поведение с помощью GsonBuilder.setPrettyPrinting ().
  • В сгенерированном JSON пропущены все пустые поля.Обратите внимание, что нулевые значения в массивах сохраняются как есть, поскольку массив представляет собой упорядоченный список.Более того, если поле не является нулевым, но его сгенерированный JSON пуст, поле сохраняется.Вы можете настроить Gson для сериализации пустых значений, установив GsonBuilder.serializeNulls ().
  • Gson обеспечивает сериализацию и десериализацию по умолчанию для Enums, Map, java.net.URL, java.net.URI, java.util.Locale.классы java.util.Date, java.math.BigDecimal и java.math.BigInteger.Если вы предпочитаете изменить представление по умолчанию, вы можете сделать это, зарегистрировав адаптер типа через GsonBuilder.registerTypeAdapter (Type, Object).
  • Формат даты по умолчанию такой же, как и у java.text.DateFormat.DEFAULT.Этот формат игнорирует миллисекундную часть даты во время сериализации.Вы можете изменить это, вызвав GsonBuilder.setDateFormat (int) или GsonBuilder.setDateFormat (String).
  • По умолчанию Gson игнорирует аннотацию com.google.gson.annotations.Expose.Вы можете разрешить Gson сериализовать / десериализовать только те поля, помеченные этой аннотацией, через GsonBuilder.excludeFieldsWithoutExposeAnnotation ().
  • По умолчанию Gson игнорирует com.google.gson.annotations.Since аннотации.Вы можете разрешить Gson использовать эту аннотацию через GsonBuilder.setVersion (double).
  • Политика именования полей по умолчанию для выходного Json такая же, как и в Java.Таким образом, поле Java версии versionNumber будет выводиться как «versionNumber @ quot» в Json. Те же правила применяются для сопоставления входящего Json с классами Java. Вы можете изменить эту политику с помощью GsonBuilder.setFieldNamingPolicy (FieldNamingPolicy).
  • По умолчанию Gson исключает переходные или статические поля из рассмотрения для сериализации и десериализации. Это поведение можно изменить с помощью GsonBuilder.excludeFieldsWithModifiers (int).

ОК, теперь япосмотрите, в чем проблема. Сериализатор карт по умолчанию, как вы и ожидали, не поддерживает вложенные карты. Как вы можете видеть в этот исходный фрагмент из DefaultTypeAdapters (особенно если вы проходите через отладчик) переменной childGenericType установлен по типу java.lang.Object по какой-то таинственной причине, поэтому тип значения времени выполнения никогда не анализируется.

Два решения, я думаю:

  1. Реализуйте свой собственный сериализатор / десериализатор карт
  2. Используйте более сложныйРед. версия вашего метода, примерно такая:

    public String toJSON(){
        final Gson gson = new Gson();
        final JsonElement jsonTree = gson.toJsonTree(General, Map.class);
        final JsonObject jsonObject = new JsonObject();
        jsonObject.add("General", jsonTree);
        return jsonObject.toString();
    }
    
4 голосов
/ 28 декабря 2010

Попробуйте:

Gson gson = new Gson();
System.out.println(gson.toJson(General));

Не уверен, что если вы все еще ищете решение, это работает для меня:

import java.util.LinkedHashMap;

import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class Example {
//  private static LinkedHashMap<String,Object> General;
    private ImmutableMap General;

    private static final String VERSION="Version";
    private static final String RANGE="Range";
    private static final String START_TIME="Start_Time";
    private static final String END_TIME="End_Time";

    public Example() {

        LinkedHashMap<String,String> Range = new LinkedHashMap<String, String>();
        Range.put(START_TIME, "now");
        Range.put(END_TIME, "never");

//        General.put(RANGE, Range);
        General = ImmutableMap.of(VERSION, "0.1", RANGE, Range);
    }

    public String toJSON() {
//        Gson gson = new GsonBuilder().serializeNulls().create();
          Gson gson = new Gson();
          return gson.toJson(this);
    }

}

возвращает: {"General": {"Version": "0.1", "Range": {"Start_Time": "now", "End_Time": "never"}}}


Очевидно, вы можете использовать ImmutableMap.copyOf(your_hashmap) здесь вместо

1 голос
/ 18 августа 2014

Более простой альтернативой было бы использование Джексона вместо GSON, сериализация вложенной карты работает из коробки:

    LinkedHashMap<String, Object> general;
    general = new LinkedHashMap<String, Object>();
    general.put("Version", "0.1");

    LinkedHashMap<String, String> Range = new LinkedHashMap<String, String>();
    Range.put("Start_Time", "now");
    Range.put("End_Time", "never");

    general.put("Range", Range);

    // Serialize the map to json using Jackson
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    new org.codehaus.jackson.map.ObjectMapper().writer().writeValue(os,
            general);       
    String json = os.toString();
    os.close();

    System.out.println(json);

Выход:

{ "Версия": "0,1", "Диапазон": { "Start_Time": "Сейчас", "END_TIME": "никогда"}}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...