Как сделать поле fieldName для fieldValue десериализацией строки json - PullRequest
2 голосов
/ 21 декабря 2010

У меня есть класс, имеющий тривиальные строковые поля и только одну карту:


class MyClass {
  @SerializedName("handle");
  String nickName;
  Map randomDetails;
} 

Мое требование - создать карту fieldName для fieldValue (Map), но fieldNames должно совпадать с @SerializedName, а не с именем поля Myclass. Я понимаю, что для такого сложного типа, как MyClass, мне, возможно, придется самостоятельно выполнить некоторую десериализацию низкого уровня. Кто-нибудь сталкивался с этим?

Ответы [ 2 ]

0 голосов
/ 10 июня 2011

(мне кажется, я понимаю, что вопрос касается того, как использовать Gson для десериализации структуры карты JSON в Java Map.)

Gson в настоящее время требуется немного больше информации о типе Map, чем обеспечивает структура класса Java в исходном вопросе. Вместо того, чтобы объявлять, что randomDetails - это обычный старый Map, пусть Гсон знает, что это Map<String, String>. Затем следующий пример JSON и простой код десериализации выполняется, как и ожидалось.

input.json Содержание:

{
  "handle":"the handle",
  "random_details":{"one":1,"too":"B","3":false,"for":5.32}
}

Foo.java:

import java.io.FileReader;
import java.util.Map;

import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;

public class Foo
{
  public static void main(String[] args) throws Exception
  {
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
    Gson gson = gsonBuilder.create();
    MyClass myObject = gson.fromJson(new FileReader("input.json"), MyClass.class);
    System.out.println(gson.toJson(myObject));
  }
}

class MyClass
{
  @SerializedName("handle")
  String nickName;
  Map<String, String> randomDetails;
}

Обратите внимание, что при этом все значения в Map преобразуются в Strings. Если вам нужно что-то более общее, например Map<String, Object>, или если randomDetails должен быть просто старый Map без дополнительной информации о типе, то необходимо реализовать пользовательскую обработку десериализации, , как описано в руководстве пользователя . (Это ситуация, когда Gson, к сожалению, в настоящее время не генерирует автоматически значения Java String или типа примитива из примитивов JSON, если объявленный тип Java просто Object. Таким образом, необходимо реализовать пользовательскую десериализацию.)

Вот один из таких примеров.

import java.io.FileReader;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.annotations.SerializedName;

public class Foo
{
  public static void main(String[] args) throws Exception
  {
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
    gsonBuilder.registerTypeAdapter(MyClass.class, new MyClassDeserializer());
    Gson gson = gsonBuilder.create();
    MyClass myObject = gson.fromJson(new FileReader("input.json"), MyClass.class);
    System.out.println(gson.toJson(myObject));
  }
}

class MyClassDeserializer implements JsonDeserializer<MyClass>
{
  @Override
  public MyClass deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException
  {
    JsonObject object = json.getAsJsonObject();
    String nickName = object.get("handle").getAsString();
    Set<Map.Entry<String, JsonElement>> mapEntries = object.get("random_details").getAsJsonObject().entrySet();
    Map randomDetails = new HashMap(mapEntries.size());
    for (Map.Entry<String, JsonElement> mapEntry : mapEntries)
    {
      String key = mapEntry.getKey();
      Object value;
      JsonPrimitive jsonPrimitive = mapEntry.getValue().getAsJsonPrimitive();
      if (jsonPrimitive.isNumber()) value = jsonPrimitive.getAsNumber();
      else if (jsonPrimitive.isBoolean()) value = jsonPrimitive.getAsBoolean();
      else value = jsonPrimitive.getAsString();
      randomDetails.put(key, value);
    }
    MyClass myObject = new MyClass();
    myObject.nickName = nickName;
    myObject.randomDetails = randomDetails;
    return myObject;
  }
}

class MyClass
{
  @SerializedName("handle")
  String nickName;
  Map randomDetails;
}
0 голосов
/ 29 марта 2011

Если вы используете библиотеку, вам не нужно выполнять любую работу низкого уровня.

Я не использовал его (пока), но Джексон выглядит так, как будто он сделает то, что вам нужно.

Было бы особенно легко, если бы вы не требовалисьиспользовать эту аннотацию @SerializedName, поскольку Джексон предоставляет набор своих собственных аннотаций , которые выполняют именно то, что вам нужно - (см. аннотацию @JsonProperty).

Если вы используете Модель дерева Джексона Режим работы, вы должны получить что-то вроде результатов на основе карт, которые вы ищете.

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