如何使fieldName to fieldValue map反序列化json字符串

时间:2010-12-21 19:46:14

标签: java json collections gson

我有一个类有简单的字符串类型字段和一个地图:


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

我的要求是创建fieldName到fieldValue(Map)的映射,但fieldNames应该与@SerializedName相同,而不是Myclass的字段名称。我意识到对于像MyClass这样的复杂类型,我可能不得不自己做一些低级反序列化。有人遇到过这个吗?

2 个答案:

答案 0 :(得分:0)

如果您使用库,则不需要执行任何低级别工作。

我尚未使用它(但是)Jackson看起来它会做你需要的。

如果您不需要使用@SerializedName注释,那将非常容易,因为杰克逊提供了一套its own annotations,可以完全满足您的需求 - (请参阅@JsonProperty注解)。

如果您使用Jackson Tree Model操作模式,您应该获得类似您正在寻找的基于地图的结果。

答案 1 :(得分:0)

(我想我明白这个问题涉及如何使用Gson将JSON地图结构反序列化为Java Map。)

Gson目前需要更多关于Map的类型信息,而不是原始问题中提供的Java类结构。不要声明randomDetails是一个普通的Map,而是让Gson知道它是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而没有其他类型信息,那么就必须实现自定义反序列化处理,{{3} }。 (如果声明的Java类型只是String,那么Gson目前不会自动从JSON原语自动生成Object或原始类型的Java值。因此,有必要实现自定义反序列化。 )

这是一个这样的例子。

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;
}