当前位置: 首页 > 面试题库 >

部分GSON反序列化

邹丰羽
2023-03-14
问题内容

JsonDeserializer由于要执行处理的业务逻辑,因此我正在实现自定义。但是某些部分可以解析为标准方式。这是否可能-
我自己处理一些元素,并让一些嵌套元素自动处理?

这是JSON:

{
  "id": "10",
  "games": ["PZ"],
  "definition":
  {
    "count": 10,
    "operatorDefinitions": [
      {
        "operators": "+",
        "first": "1-5",
        "second": "1-5",
        "result": "2-5"
      }
    ]
  }

这是definition项的自定义反序列化器:

public class FormulaDefinitionGsonAdapter implements JsonDeserializer<FormulaDefinition> {
public FormulaDefinition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
    FormulaDefinition definition = new FormulaDefinition();
    JsonObject jsonObject = json.getAsJsonObject();
    JsonPrimitive p = jsonObject.getAsJsonPrimitive("count");
    definition.setCount(p.getAsInt());

    JsonArray array = jsonObject.getAsJsonArray("operatorDefinitions");
    if (array == null || array.size() == 0) {
        throw new JsonParseException("Element 'operatorDefinitions' is missing!");
    }

    for (JsonElement jsonElement : array) {
        jsonObject = (JsonObject) jsonElement;
        p = jsonObject.getAsJsonPrimitive("first");
        String sValues = p.getAsString();
        Values firstArgValues = Values.parse(sValues);

现在,我想让GSON解析operators枚举。我可以自己完成,这只是几行代码,但是我更愿意库做很多。


问题答案:

…但是我希望图书馆尽其所能。

好吧,只需使用Gson。

有数据传输对象模式,尤其是Gson映射类,可以完美地解决您的问题。默认情况下,如果Gson能够满足内置功能的映射,并且除了特殊情况外,您不必自己完成工作。此类映射类仅旨在存在于JSON内容和您的业务对象类之间,以便对数据进行(反)序列化(简单地说,DTO仅为此目的而存在,并且与Gson相关的注释不得散布到您的业务类中-
只需将DTO转换为业务对象)。

对应

final class Wrapper {

    @SerializedName("id")
    @Expose
    private final String id = null;

    @SerializedName("games")
    @Expose
    private final List<String> games = null;

    @SerializedName("definition")
    @Expose
    private final FormulaDefinition formulaDefinition = null;

    private Wrapper() {
    }

    @Override
    public String toString() {
        return new StringBuilder("Wrapper{")
                .append("id='").append(id)
                .append("', games=").append(games)
                .append(", formulaDefinition=").append(formulaDefinition)
                .append('}')
                .toString();
    }

}



package q41323887;

import java.util.List;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

final class FormulaDefinition {

    @SerializedName("count")
    @Expose
    private /*final*/ int count /*= 0*/; // Gson works with final primitives like `int` strangely

    @SerializedName("operatorDefinitions")
    @Expose
    private final List<OperatorDefinition> operatorDefinitions = null;

    private FormulaDefinition() {
    }

    @Override
    public String toString() {
        return new StringBuilder("FormulaDefinition{")
                .append("count=").append(count)
                .append(", operatorDefinitions=").append(operatorDefinitions)
                .append('}')
                .toString();
    }

}



final class OperatorDefinition {

    @SerializedName("operators")
    @Expose
    private final Operator operators = null;

    @SerializedName("first")
    @Expose
    private final String first = null;

    @SerializedName("second")
    @Expose
    private final String second = null;

    @SerializedName("result")
    @Expose
    private final String result = null;

    private OperatorDefinition() {
    }

    @Override
    public String toString() {
        return new StringBuilder("OperatorDefinition{")
                .append("operators=").append(operators)
                .append(", first='").append(first)
                .append("', second='").append(second)
                .append("', result='").append(result)
                .append("'}")
                .toString();
    }

}



enum Operator {

    PLUS("+"),
    MINUS("-"),
    ASTERISK("*"),
    SLASH("/");

    private static final Map<String, Operator> tokenToOperatorIndex = createTokenToOperatorIndexInJava8();

    private final String token;

    Operator(final String token) {
        this.token = token;
    }

    static Operator resolveOperator(final String token)
            throws NoSuchElementException {
        final Operator operator = tokenToOperatorIndex.get(token);
        if ( operator == null ) {
            throw new NoSuchElementException("Cannot resolve operator by " + token);
        }
        return operator;
    }

    private static Map<String, Operator> createTokenToOperatorIndex() {
        final Map<String, Operator> index = new HashMap<>();
        for ( final Operator operator : values() ) {
            index.put(operator.token, operator);
        }
        return unmodifiableMap(index);
    }

    private static Map<String, Operator> createTokenToOperatorIndexInJava8() {
        final Map<String, Operator> index = Stream.of(values())
                .collect(toMap(operator -> operator.token, identity()));
        return unmodifiableMap(index);
    }

}

反序列化

然后,由于您本operators打算成为有效的枚举,因此这是您真正需要自定义JSON反序列化器的唯一地方,仅因为Gson默认规则不了解这些规则。

final class OperatorJsonDeserializer
        implements JsonDeserializer<Operator> {

    private static final JsonDeserializer<Operator> operatorJsonDeserializer = new OperatorJsonDeserializer();

    private OperatorJsonDeserializer() {
    }

    static JsonDeserializer<Operator> getOperatorJsonDeserializer() {
        return operatorJsonDeserializer;
    }

    @Override
    public Operator deserialize(final JsonElement json, final Type type, final JsonDeserializationContext context)
            throws JsonParseException {
        try {
            final String token = json.getAsJsonPrimitive().getAsString();
            return resolveOperator(token);
        } catch ( final NoSuchElementException ex ) {
            throw new JsonParseException(ex);
        }
    }

}

演示版

现在,您可以使用Wrapper该类反序列化JSON:

// Gson instances are thread-safe and can be easily instantiated once
private static final Gson gson = new GsonBuilder()
        .registerTypeAdapter(Operator.class, getOperatorJsonDeserializer())
        .create();

public static void main(final String... args)
        throws IOException {
    try ( final Reader reader = new InputStreamReader(EntryPoint.class.getResourceAsStream("/test.json")) ) {
        final Wrapper wrapper = gson.fromJson(reader, Wrapper.class);
        out.println(wrapper);
        // ... convert the wrapper DTO above to your target business object
    }
}

输出:

包装器{id = ‘10’,游戏= [PZ],FormulaDefinition = FormulaDefinition {count =
10,operatorDefinitions = [OperatorDefinition {operators = PLUS,first
=‘1-5’,second =‘1-5’,result =’ 2-5’}]}}

编辑

我在以下代码片段中对Gson的理解是错误的:

    @SerializedName("count")
    @Expose
    private /*final*/ int count /*= 0*/; // Gson works with final primitives like `int` strangely

实际上,Gson 确实
工作正常。我忘记了Java常量内联。使用获得count通孔反射Field效果完美。但是,由于内联,返回了contant值。与相似的普通对象javap -p -c

final class ext.Test$Immutable {
  private final int foo;

  private ext.Test$Immutable();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: iconst_0
       6: putfield      #2                  // Field foo:I
       9: return

  private int getFoo();
    Code:
       0: iconst_0
       1: ireturn

  public java.lang.String toString();
    Code:
       0: ldc           #4                  // String (IMMUTABLE:0)
       2: areturn
}

在这种情况下,甚至toString()返回一个常数。是的,这就是Java和javac工作方式。为了禁用这种内联并将final修饰符添加到该字段,就像周围的所有字段一样,应添加一个非编译时值:

    @SerializedName("count")
    @Expose
    private final int count = constOf(0);

哪里constOf(int)仅仅是:

private static int constOf(final int value) {
    return value;
}

现在,所有传入的DTO字段都可以轻松声明final



 类似资料:
  • 问题内容: 我想通过Google Gson传输列表对象,但是我不知道如何反序列化泛型类型。 看了这个之后我尝试了什么(BalusC的答案): 但是后来我在日食中遇到了一个错误,说“新的List(){}类型必须实现继承的抽象方法…”,如果我使用快速修复方法,则会得到20个以上的方法存根的怪物。 我很确定有一个更简单的解决方案,但是我似乎找不到它! 编辑: 我现在有 但是,我确实在“ fromJson

  • 我正在尝试使用gson从JSON对象反序列化数据。我有麻烦1)设计一个类。2)从内部列表对象获得一个空对象。 以下是JSON对象的示例 下面是我为json对象创建的类的一个示例,该类将与使用java的gson一起使用 下面是使用gson的示例代码 任何帮助都将不胜感激,我对GSON和检索JSON对象非常陌生。非常感谢你

  • 我想使用Gson将JSON反序列化为对象。我已经定义了相应的类,其中一些类的对象包含在其他对象中。在尝试反序列化整个JSON时,我得到了空值,所以我开始将其拆分。 我已经到了所有低级类都支持自己的地步,但是当我试图反序列化成一个包含那个较小对象的实例的对象时,所有的东西都返回为null。 我的部分JSON: UserProfile类: UPfield类: 用户类: Ufield类: 我的主要观点是

  • 问题内容: 我使用了很多不可变的集合,并且很好奇如何使用Gson反序列化它们。由于没有人回答,而且我自己找到了解决方案,因此我正在简化问题并提出自己的答案。 我有两个问题: 如何为所有人编写一个作品? 如何全部注册? 问题答案: 更新:有https://github.com/acebaggins/gson- serializers ,其中涵盖了许多番石榴集合: 如何编写适用于所有Immutable

  • 问题内容: 我正在使用GSON 1.4,并使用两个通用对象序列化对象,如下所示 。当我对它进行反序列化时 可悲的是我得到了 java.lang.IllegalArgumentException:无法将java.util.ArrayList字段…设置为java.util.LinkedList 这是为什么 ?GSON文档指出,如果我使用object.class参数进行序列化,则它支持泛型。任何想法?谢

  • 我有一个Api,Api如下所示: 如果响应是ok,那么结构将以关键字开头,例如: 问题是:我如何为父类创建一个反序列化器,它也会反序列化子类(作为我的第二种方法),或者我如何用Gson创建一个泛型类,这样包装在周围的每个tyoe都可以与它一起使用,比如: public class DataObjectDeserializer implements JsonDeserializer{