【问题标题】:Check if json property is present, is string, and is correct value检查 json 属性是否存在、是否为字符串、是否为正确值
【发布时间】:2017-01-31 08:52:44
【问题描述】:

使用 gson,我使用这种繁琐的方法来确保所需的属性具有所需的值:

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

public class ScratchSpace {

    public static void main(String[] args) {

        // create json object from source data - in my real code, this is sourced externally
        JsonObject json = new JsonParser().parse("{  \"product\": \"foobar\"}").getAsJsonObject();

        // does this object have a key called product, which is a string, and equal to our expected value?
        boolean correctProduct = false;
        if (json.has("product")) {
            JsonElement productElement = json.get("product");
            if (productElement.isJsonPrimitive()) {
                String product = productElement.getAsString();
                if ("foobar".equals(product)) {
                    correctProduct = true;
                }

            }
        }
        System.out.println("correctProduct = " + correctProduct);
    }

}

我几乎可以肯定我做得不够理想。是否有一个简单、易读、简短的单行代码来实现相同的目标?

编辑:如果可能,我想继续使用 gson。

【问题讨论】:

标签: java json gson


【解决方案1】:

使用java.util.Optional,以下工作:

final boolean correctProduct = Optional.ofNullable(json.get("product"))
            .filter(JsonPrimitive.class::isInstance)
            .map(JsonPrimitive.class::cast)
            .map(JsonPrimitive::getAsString)
            .filter("foobar"::equals)
            .isPresent();

【讨论】:

  • 使用流是一种有趣的方法;我期待 gson 也有一些方便的方法来做到这一点。
  • 实际上,javax.json.JsonObject 有一个 getString 方法,如果该值不是 String,则可能有默认值,但显然,Google 宁愿创建自己的数据模型... ;- ) PS.:如果有更多的开发人员从“在错误情况下返回 null”转向“返回一个可选”方案,我会很高兴。
  • @Smutje AFAIR,JSON 处理甚至在 Java 8 之前就被引入了 Java 7 及其选项,而 Gson 最初是在大约十年前的 2008 年发布的,所以我认为 javax.json 的作者只是重新考虑了 Gson 或 Jackson 等现有库。返回null 更便宜,但是如果一个人更喜欢oneliners,那么在这种情况下就不那么方便了......
  • 好的,这将解释 Java 中 JSON 表示的差异。
【解决方案2】:

我知道你说的是 GSON,但是 jackson 提供的基于 pojo 的方法让你想做的事情太方便了以至于不能不发帖:

简单的pojo:

public class FooPojo {
    @JsonProperty
    private String product;

    public String getProduct() {
        return product;
    }

    public void setProduct(String product) {
        this.product = product;
    }

    public boolean isProductEqualTo(String check) {
        return product.equals(check);
    }
}

解析和检查:

public static void main(String[] args) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    FooPojo fooPojo = objectMapper.readValue("{  \"product\": \"foobar\"}", FooPojo.class);
    System.out.println(fooPojo.isProductEqualTo("foobar"));
}

【讨论】:

    【解决方案3】:

    你可以像this这样写一个自定义的反序列化器,注册它,然后使用fromJson方法直接从json字符串中获取对象。这样,如果json字符串不是预期的格式,您可以返回null或在反序列化器中抛出异常。

    请注意,您不必单独设置每个字段。执行自定义检查后,您可以使用来自context 的默认反序列化。

    编辑:如果您只想获得true/false 而不是完整的对象,那么您可以编写一个MyBoolean 类,持有一个简单的boolean 值并使用fromJson 方法反序列化为 MyBoolean 类。自定义反序列化程序将仅执行所需的检查并适当地设置 MyBoolean 实例的内容。此外,(我猜)如果你从布尔值扩展这个MyBoolean,你也可以将它用作boolean

    编辑 2:我之前没有时间包含示例代码。这是我的建议:

    package io.ram.ram;
    
    import java.lang.reflect.Type;
    
    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.JsonParseException;
    
    public class Tester {
    
        public static class MyBoolean {
            private boolean value;
    
            public void set(boolean value) {
                this.value = value;
            }
    
            public boolean get() {
                return value;
            }
        }
    
        public static class MyAdapter implements JsonDeserializer<MyBoolean> {
    
            public MyBoolean deserialize(JsonElement json, Type type, JsonDeserializationContext context)
                    throws JsonParseException {
                MyBoolean result = new MyBoolean();
                result.set(false);
    
                try {
                    result.set(json.getAsJsonObject().get("product").getAsString().equals("foobar"));
                } catch (Exception e) {
    
                }
                return result;
            }
    
        }
    
        public static void main(String[] args) {
            Gson gson = new GsonBuilder().registerTypeAdapter(MyBoolean.class, new MyAdapter()).create();
    
            System.out.println(gson.fromJson("{\"product\": \"foobar\"}", MyBoolean.class).get());
            System.out.println(gson.fromJson("{\"product\": \"foobaz\"}", MyBoolean.class).get());
        }
    
    }
    

    正如我所说,在您为自定义序列化注册类型适配器后,您可以通过一行代码实现您想要的。 (注意:布尔类是最终的,所以我们不能扩展它。抱歉这个错误信息。)

    当然,您可以为字符串 "product""foobar" 参数化 MyAdapter,因此您不必为每种可能的情况都创建此类。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-22
      • 2011-11-18
      • 1970-01-01
      • 2019-06-27
      相关资源
      最近更新 更多