当前位置: 首页 > 知识库问答 >
问题:

有没有办法忽略Gson中的JsonSyntaxException

仉洲
2023-03-14

我有一个json看起来像这样:

[
{
_id: "54b8f62fa08c286b08449b8f",
loc: [
   36.860983,
   31.0567
]
},
{
_id: "54b8f6aea08c286b08449b93",
loc: {
coordinates: [ ]
}
}
]

如您所见,loc对象有时是json对象,有时是双数组。在不编写自定义反序列化程序的情况下,有没有办法避免JsonSyntaxException,并在loc对象是json对象而不是双数组时将其设置为null。

共有2个答案

颜宸
2023-03-14

我是这样做的。它更短,但我认为@DevrimTuncers的答案是最好的。

//This is just Double array to use as location object
public class Location extends ArrayList<Double> {
    public Double getLatidute() {
        if (this.size() > 0) {
            return this.get(0);
        } else {
            return (double) 0;
        }
    }

    public Double getLongitude() {
        if (this.size() > 1) {
            return this.get(1);
        } else {
            return (double) 0;
        }
    }

    public static class LocationDeserializer implements JsonDeserializer<Location> {
        @Override
        public Location deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            try {
                JsonArray array = json.getAsJsonArray();
                Location location = new Location();
                for (int i = 0; i < array.size(); i++) {
                    location.add(array.get(i).getAsDouble());
                }

                return location;
            } catch (Exception e) {
                return null;
            }
        }
    }
}
卫嘉佑
2023-03-14

对于json值的特定字段的自定义序列化/反序列化,没有任何简单的方法(我指的是Gson的属性/方法调用)。

您可以看到com.google.gson.internal.bind.ReflecteTypeAdapterFactory的源代码,并在其html" target="_blank">内部类Adapter的read方法上进行调试。

您可以读取特定字段的自定义序列化并跟踪其链接。它可能会在Gson的未来版本中实现。(最新版本2.2.4不提供)

我会为此编写一些代码。也许这不是你想要的,但它可能会帮助其他人。)

解决方案1(与第二个解决方案相比,它的代码更少,但第二个解决方案的性能要好得多):

public class SubClass extends BaseClass {
    private double[] loc;
}

public class BaseClass {
    @SerializedName("_id")
    private String id;
}

public class CustomTypeAdapter extends TypeAdapter<BaseClass> {
    private Gson gson;
    public CustomTypeAdapter() {
        this.gson = new Gson();
    }

    @Override
    public void write(JsonWriter out, BaseClass value)
            throws IOException {
        throw new RuntimeException("Not implemented for this question!");
    }

    @Override
    public BaseClass read(JsonReader in) throws IOException {
        BaseClass instance;
        try {
            instance = gson.fromJson(in, SubClass.class);
        } catch (Exception e) {
            e.printStackTrace();
            instance = gson.fromJson(in, BaseClass.class);
        }
        return instance;
    }
}

测试:

private void test() {
    String json = "[{_id:\"54b8f62fa08c286b08449b8f\",loc:[36.860983,31.0567]},{_id:\"54b8f6aea08c286b08449b93\",loc:{coordinates:[]}}]";

    Type collectionType = new TypeToken<List<BaseClass>>(){}.getType();
    Gson gson = new GsonBuilder().registerTypeAdapter(BaseClass.class, new CustomTypeAdapter()).create();
    List<BaseClass> list = gson.fromJson(json, collectionType);

    for(BaseClass item : list) {
        if(item instanceof SubClass) {
            System.out.println("item has loc value");
            SubClass subClassInstance = (SubClass)item;
        } else {
            System.out.println("item has no loc value");
            BaseClass baseClassInstance = item;
        }
    }
}

解决方案2(这是Gson开发者的建议之一,请参阅原始帖子):

将下面的内容复制到你的项目中。它将成为定制TypeAdapterFactory的基类。

public abstract class CustomizedTypeAdapterFactory<C>
        implements TypeAdapterFactory {
    private final Class<C> customizedClass;

    public CustomizedTypeAdapterFactory(Class<C> customizedClass) {
        this.customizedClass = customizedClass;
    }

    @SuppressWarnings("unchecked") // we use a runtime check to guarantee that 'C' and 'T' are equal
    public final <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        return type.getRawType() == customizedClass
                ? (TypeAdapter<T>) customizeMyClassAdapter(gson, (TypeToken<C>) type)
                : null;
    }

    private TypeAdapter<C> customizeMyClassAdapter(Gson gson, TypeToken<C> type) {
        final TypeAdapter<C> delegate = gson.getDelegateAdapter(this, type);
        final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
        return new TypeAdapter<C>() {
            @Override public void write(JsonWriter out, C value) throws IOException {
                JsonElement tree = delegate.toJsonTree(value);
                beforeWrite(value, tree);
                elementAdapter.write(out, tree);
            }
            @Override public C read(JsonReader in) throws IOException {
                JsonElement tree = elementAdapter.read(in);
                afterRead(tree);
                return delegate.fromJsonTree(tree);
            }
        };
    }

    /**
     * Override this to muck with {@code toSerialize} before it is written to
     * the outgoing JSON stream.
     */
    protected void beforeWrite(C source, JsonElement toSerialize) {
    }

    /**
     * Override this to muck with {@code deserialized} before it parsed into
     * the application type.
     */
    protected void afterRead(JsonElement deserialized) {
    }
}

编写您的POJO和自定义自定义类型适配器工厂。重写后读取方法并处理双数组,如您在问题中所问:

public class MyClass {
    @SerializedName("_id")
    private String id;
    private double[] loc;
    // getters/setters
}

private class MyClassTypeAdapterFactory extends CustomizedTypeAdapterFactory<MyClass> {
    private MyClassTypeAdapterFactory() {
        super(MyClass.class);
    }

    @Override protected void afterRead(JsonElement deserialized) {
        try {
            JsonArray jsonArray = deserialized.getAsJsonObject().get("loc").getAsJsonArray();

            System.out.println("loc is not a double array, its ignored!");
        } catch (Exception e) {
            deserialized.getAsJsonObject().remove("loc");
        }
    }
}

测试:

private void test() {
    String json = "[{_id:\"54b8f62fa08c286b08449b8f\",loc:[36.860983,31.0567]},{_id:\"54b8f6aea08c286b08449b93\",loc:{coordinates:[]}}]";

    Gson gson = new GsonBuilder()
            .registerTypeAdapterFactory(new MyClassTypeAdapterFactory())
            .create();

    Type collectionType = new TypeToken<List<MyClass>>(){}.getType();
    List<MyClass> list = gson.fromJson(json, collectionType);

    for(MyClass item : list) {
        if(item.getLoc() != null) {
            System.out.println("item has loc value");
        } else {
            System.out.println("item has no loc value");
        }
    }
}
 类似资料:
  • 问题内容: 使用PMD,如果要忽略特定的警告,则可以使该行被忽略。 FindBugs有类似的东西吗? 问题答案: FindBugs的初始方法涉及XML配置文件(也称为过滤器)。这确实不如PMD解决方案方便,但是FindBugs只能在字节码上工作,而不能在源代码上工作,因此注释显然不是一个选择。例: 但是,为解决此问题,FindBugs稍后引入了另一个基于注释的解决方案(请参阅参考资料),您可以在类

  • 问题内容: 我正在使用MySQL GUI,通过选择某些表并将从备份转储生成的语句运行到空表(新模式)中,以将某些站点迁移到CMS的新版本。旧表中有几列在新表中不存在,因此脚本会因以下错误而停止: 脚本行:1个“字段列表”中的未知列“ user_id” 挑选要导出的所需列,或编辑转储文件将非常乏味且耗时。要解决此问题,我将在生成错误时创建未使用的列,通过运行查询导入数据,然后在处理完该表后删除未使用

  • 问题内容: 是否有可能以某种方式忽略此错误?我发现将自己不想运行的代码放在前面比注释它要容易得多(当注释重叠并且表现不佳时)… 问题答案: 否。这是编译时错误。因此,在运行课程之前,您 必须 摆脱它。 我通常要做的是在其前面放置一个虚假陈述。就像是: 使用此代码,您将不会出错。您将得到想要的东西。

  • 我正在尝试创建一个通用的绑定文件,在多个项目中从WSDLs/XSD生成一致的Java类。我们通过(由@lexicore制作)生成代码。 问题在于多项目部分。如果特定的绑定指令与提供的XSD或WSDL中的任何内容都不匹配,则类生成失败 对“

  • 在加载时,Spring容器初始化bean。。。当它发现与Bean相关的错误时,它会停止并回滚(不是确切的术语)。。。我知道。 这是我们的条件。我们正在开发一种网络应用系统。(它很大)有几千个Spring bean。我们的客户要求如下。“在WAS重启过程中,即使一个或几个Bean有问题(加载时错误),忽略这些,系统必须继续......” 我们已经通过修改Spring的源代码满足了这个要求。。。但我认

  • 我可以在写入之前读取表,并在写入新行之前删除匹配行。 阅读后,我可以筛选应用程序中的行。 我不喜欢这两个解决方案,因为它们似乎太复杂了,性能是一个很大的问题。有更好的办法吗?