如果json格式有效,Java将忽略GSON上的自定义反序列化

jexiocij  于 2023-08-05  发布在  Java
关注(0)|答案(2)|浏览(138)

我一直在寻找周围,但无法找到任何结论,我的问题,我会尽量描述它的最好的方式,我可以。
我调用了一个API,它可以以两种方式响应(* 注意,类名只是示例,而不是真实的的名字 *):
不良React:

{
        "CustomObject_1" : {
            "CustomObject_1.1" : {
                ...
            },
            "CustomObject_1.2" : [
                [ ]
            ]
        },
        "CustomObject_2" : {
            ...
        }

字符串
良好React:

{
        "CustomObject_1" : {
            "CustomObject_1.1" : {
                ...
            },
            "CustomObject_1.2" : [
                "CustomObject_1.2.1" : {
                ...
                }
            ]
        },
        "CustomObject_2" : {
            ...
        }


不同之处在于CustomObject_1.2可以是一个自定义对象(内部包含更多层的自定义对象),也可以是一个空数组。
我有一个反序列化器,它可以纠正错误的响应,但它会使正确的响应为null,而不是使用默认的序列化。
class CustomObject_1.2Deserializer

public CustomObject_1.2 deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
        if (json.isJsonArray()) {
            JsonArray jsonArray = json.getAsJsonArray();
            if (jsonArray.size() == 0) {
                System.out.println(jsonArray);  // return an empty Totals object
                return new CustomObject_1.2();
            }
        } else if (json.isJsonObject()) {
            JsonObject jsonObject = json.getAsJsonObject();
            if (jsonObject.has("CustomObject_1.2.1") && jsonObject.get("CustomObject_1.2.1").isJsonArray()) {
                JsonArray competitorsArray = jsonObject.getAsJsonArray("competitors");
                System.out.println(competitorsArray);   //valid object so use default serialization
            }
        }
        return null;
    }


当json是一个有效的对象时,有没有办法忽略反序列化?
如果需要,这里是处理gson序列化的函数:

private MyDtoInterface processResponse(String message) {
        MyDtoInterface mDto = null;
        try {
                Gson gson = new GsonBuilder()
                        .registerTypeAdapter(CustomObject_1.2.class, new CustomObject_1.2Deserializer())
                        .create();
                mDto = gson.fromJson(message, CustomparentDTO.class);
        } catch (Exception e) {
            System.out.println("Json format not compatible with ParentDTO");
        }
        return mDto;
    }


在此先谢谢您!
我都不知道我试过什么了。我能找到的大多数例子都使用原语,而不是CustomObjects中的CustomObjects。
我只尝试反序列化无效的json。如果我试图构建一个new CustomObject_1.2(),它将是无止境的,因为它的属性不是像String,Integer,Date等原语。它们是对象内部的自定义对象。
上面的代码将返回以下内容:不良响应(将构建良好的DTO):

{
        "CustomObject_1" : {
            "CustomObject_1.1" : {
                ...
            },
            "CustomObject_1.2" : [
                "CustomObject_1.2.1" : null
            ]
        },
        "CustomObject_2" : {
            ...
        }


良好响应(将构建空DTO):

{
        "CustomObject_1" : {
            "CustomObject_1.1" : {
                ...
            },
            "CustomObject_1.2" : [
                All elements are null
            ]
        },
        "CustomObject_2" : {
            ...
        }

llmtgqce

llmtgqce1#

我已经改变了我的反序列化器代码如下,它看起来像它应该工作,虽然我不确定它是否有意义。

public CustomObject_1.2 deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
    if (json.isJsonArray()) {
        JsonArray jsonArray = json.getAsJsonArray();
        if (jsonArray.size() == 0) {
            System.out.println(jsonArray);  // return an empty Totals object
            return new CustomObject_1.2();
        }
    } else if (json.isJsonObject()) {
        JsonObject jsonObject = json.getAsJsonObject();
        if (jsonObject.has("CustomObject_1.2.1") && jsonObject.get("CustomObject_1.2.1").isJsonArray()) {
            JsonArray competitorsArray = jsonObject.getAsJsonArray("competitors");
            System.out.println(competitorsArray);   //valid object so use default serialization
            return new Gson.fromJson(jsonObject, CustomObject_1.2.class);
        }
    }
    return null;
}

字符串

ilmyapht

ilmyapht2#

您的问题有点类似于this question,其中应该反序列化单个对象或对象数组。因此,对此的解决方案也是类似的:
您可以创建一个自定义的TypeAdapterFactory,其创建的适配器可以查看JSON数据。如果它找到一个JSON数组,它会期望该数组为空,并返回new CustomObject_1_2();否则它将反序列化委托给实际的适配器(如果您没有指定,Gson默认使用反射)。
与您的代码相比,它的优势在于它使用TypeAdapterFactoryTypeAdapter而不是JsonDeserializer,因此可能更高效,因为它直接对JSON数据流进行操作,并且它重用了相同的Gson示例,因此还考虑了您可能为CustomObject_1_2的字段类型注册的任何自定义适配器。
举例来说:

class CustomObject_1_2_AdapterFactory implements TypeAdapterFactory {
    public static final CustomObject_1_2_AdapterFactory INSTANCE = new CustomObject_1_2_AdapterFactory();

    private CustomObject_1_2_AdapterFactory() { }

    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        // Only handle CustomObject_1_2, let other factories handle all other types
        if (type.getRawType() != CustomObject_1_2.class) {
            return null;
        }

        TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
        return new TypeAdapter<T>() {
            @Override
            public T read(JsonReader in) throws IOException {
                if (in.peek() == JsonToken.BEGIN_ARRAY) {
                    // Expecting an empty JSON array
                    in.beginArray();
                    in.endArray();

                    // Cast is safe because factory checked that type is CustomObject_1_2
                    @SuppressWarnings("unchecked")
                    T t = (T) new CustomObject_1_2();
                    return t;
                } else {
                    return delegate.read(in);
                }
            }

            @Override
            public void write(JsonWriter out, T value) throws IOException {
                delegate.write(out, value);
            }
        };
    }
}

字符串
然后像这样注册:

Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(CustomObject_1_2_AdapterFactory.INSTANCE)
    .create();


如果您不仅需要区分数据是JSON数组还是JSON对象,还需要额外的检查,例如代码中显示的CustomObject_1.2.1属性,那么它会更复杂,因为您必须首先将JSON数据解析为JsonObject以查看字段。

相关问题