用Google的Gson严格分析JSON? [英] Strict JSON parsing with Google's Gson?

查看:112
本文介绍了用Google的Gson严格分析JSON?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我使用Google的Gson库将JSON解析为Java数据结构。

如果有一个Java字段有一个简单的方法来抛出异常没有相应的JSON?也就是说,我希望要求JSON具有Java结构中的所有字段。

解决方案

Gson没有JSON模式验证功能用于指定特定元素必须存在,并且它没有办法指定必须填充Java成员。可能有这样的功能可用,比如使用 @Required 注释。请前往 Gson问题列表,并提出增强请求。



使用Gson,您可以执行指定的JSON元素与自定义的反序列化器一起存在。

  //输出:
// [MyObject:element1 = value1,element2 = value2,element3 = value3]
// [MyObject:element1 = value1,element2 = value2,element3 = null]
//线程main中的异常com.google.gson.JsonParseException:必填字段未找到:element2

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

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;

public class Foo
{
static String jsonInput1 ={\element1 \:\value1 \,\element2 \: \ value2\,\ element3\:\ value3\};
static String jsonInput2 ={\element1 \:\value1 \,\element2 \:\value2 \};
static String jsonInput3 ={\element1 \:\value1 \,\element3 \:\value3 \};

public static void main(String [] args)
{
GsonBuilder gsonBuilder = new GsonBuilder();
MyDeserializer deserializer = new MyDeserializer();
deserializer.registerRequiredField(element2);
gsonBuilder.registerTypeAdapter(MyObject.class,deserializer);
Gson gson = gsonBuilder.create();
MyObject object1 = gson.fromJson(jsonInput1,MyObject.class);
System.out.println(object1);
MyObject object2 = gson.fromJson(jsonInput2,MyObject.class);
System.out.println(object2);
MyObject object3 = gson.fromJson(jsonInput3,MyObject.class);
System.out.println(object3);
}
}

class MyObject
{
String element1;
String element2;
String element3;

@Override
public String toString()
{
return String.format(
[MyObject:element1 =%s,element2 =%s ,element3 =%s],
element1,element2,element3);
}
}

类MyDeserializer实现了JsonDeserializer< MyObject>
{
列表< String> requiredFields = new ArrayList< String>();

void registerRequiredField(String fieldName)
{
requiredFields.add(fieldName);

$ b @Override
public MyObject反序列化(JsonElement json,类型typeOfT,JsonDeserializationContext上下文)
抛出JsonParseException
{
JsonObject jsonObject = (JsonObject)json;
for(String fieldName:requiredFields)
{
if(jsonObject.get(fieldName)== null)
{
throw new JsonParseException(Required Field Not Found :+ fieldName);
}
}
返回新的Gson()。fromJson(json,MyObject.class);
}
}

更好的方法可能是使用API JSON模式验证。 杰克逊至少有一个基本的实施可用 JSON工具看起来比较成熟。



这是杰克逊的一个例子。

  //输出:
//验证jsonInput1 ...
/ /验证jsonInput2 ...
//验证jsonInput3 ...
// $ .element2:缺失并且不是可选
// [MyObject:element1 = value1,element2 = value2 ,element3 = value3]
// [MyObject:element1 = value1,element2 = value2,element3 = null]
// [MyObject:element1 = value1,element2 = null,element3 = value3]

import java.util.List;

导入org.codehaus.jackson.map.ObjectMapper;

导入eu.vahlas.json.schema.JSONSchema;
import eu.vahlas.json.schema.JSONSchemaProvider;
import eu.vahlas.json.schema.impl.JacksonSchemaProvider;

public class Foo
{
static String jsonSchema =
{+
\description \:\Serialized MyObject规格\,+
\type\:[\object \],+
\properties \:+
{+
\element1 \:{\type \:\string \},+
\element2 \ :{\type \:\string \,\optional \:false},+
\element3 \:{\type \\ \\:\string \,\optional \:true}+
}+
};;

static String jsonInput1 ={\element1 \:\value1 \,\element2 \:\value2 \,\element3 \ :\ value3\ };
static String jsonInput2 ={\element1 \:\value1 \,\element2 \:\value2 \};
static String jsonInput3 ={\element1 \:\value1 \,\element3 \:\value3 \};

public static void main(String [] args)抛出异常
{
ObjectMapper mapper = new ObjectMapper();
JSONSchemaProvider schemaProvider = new JacksonSchemaProvider(mapper);
JSONSchema schema = schemaProvider.getSchema(jsonSchema);

System.out.println(Validating jsonInput1 ...);
validateAndLogErrors(jsonInput1,schema);
System.out.println(Validating jsonInput2 ...);
validateAndLogErrors(jsonInput2,schema);
System.out.println(Validating jsonInput3 ...);
validateAndLogErrors(jsonInput3,schema);

MyObject object1 = mapper.readValue(jsonInput1,MyObject.class);
System.out.println(object1);
MyObject object2 = mapper.readValue(jsonInput2,MyObject.class);
System.out.println(object2);
MyObject object3 = mapper.readValue(jsonInput3,MyObject.class);
System.out.println(object3);


static void validateAndLogErrors(String jsonInput,JSONSchema schema)
{
List< String> errors = schema.validate(jsonInput);
for(String error:errors)
{
System.out.println(error);
}
}
}

class MyObject
{
String element1;
String element2;
String element3;

void setElement1(String element1)
{
this.element1 = element1;
}

void setElement2(String element2)
{
this.element2 = element2;
}

void setElement3(String element3)
{
this.element3 = element3;

$ b @Override
public String toString()
{
return String.format(
[MyObject:element1 =%s ,element2 =%s,element3 =%s],
element1,element2,element3);
}
}


Suppose I am using Google's Gson library to parse JSON into Java data structures.

Is there an easy way to throw an exception if there is a Java field that has no corresponding JSON? That is, I wish to require the JSON to have all the fields in the Java structure.

解决方案

Gson doesn't have a JSON schema validation feature to specify that a particular element must be present, and it doesn't have a way to specify that a Java member must be populated. It might be nice to have such a feature available, such as with an @Required annotation. Head on over to the Gson Issues List and put in an enhancement request.

With Gson, you could enforce that specified JSON elements are present with a custom deserializer.

// output: 
//   [MyObject: element1=value1, element2=value2, element3=value3]
//   [MyObject: element1=value1, element2=value2, element3=null]
//   Exception in thread "main" com.google.gson.JsonParseException: Required Field Not Found: element2

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

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;

public class Foo
{
  static String jsonInput1 = "{\"element1\":\"value1\",\"element2\":\"value2\",\"element3\":\"value3\"}";
  static String jsonInput2 = "{\"element1\":\"value1\",\"element2\":\"value2\"}";
  static String jsonInput3 = "{\"element1\":\"value1\",\"element3\":\"value3\"}";

  public static void main(String[] args)
  {
    GsonBuilder gsonBuilder = new GsonBuilder();
    MyDeserializer deserializer = new MyDeserializer();
    deserializer.registerRequiredField("element2");
    gsonBuilder.registerTypeAdapter(MyObject.class, deserializer);
    Gson gson = gsonBuilder.create();
    MyObject object1 = gson.fromJson(jsonInput1, MyObject.class);
    System.out.println(object1);
    MyObject object2 = gson.fromJson(jsonInput2, MyObject.class);
    System.out.println(object2);
    MyObject object3 = gson.fromJson(jsonInput3, MyObject.class);
    System.out.println(object3);
  }
}

class MyObject
{
  String element1;
  String element2;
  String element3;

  @Override
  public String toString()
  {
    return String.format(
        "[MyObject: element1=%s, element2=%s, element3=%s]",
        element1, element2, element3);
  }
}

class MyDeserializer implements JsonDeserializer<MyObject>
{
  List<String> requiredFields = new ArrayList<String>();

  void registerRequiredField(String fieldName)
  {
    requiredFields.add(fieldName);
  }

  @Override
  public MyObject deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException
  {
    JsonObject jsonObject = (JsonObject) json;
    for (String fieldName : requiredFields)
    {
      if (jsonObject.get(fieldName) == null)
      {
        throw new JsonParseException("Required Field Not Found: " + fieldName);
      }
    }
    return new Gson().fromJson(json, MyObject.class);
  }
}

A preferable approach might be to use an API that provides JSON Schema validation. Jackson has at least a rudimentary implementation available. JSON Tools looks to have a more mature one.

Here's an example with Jackson.

// output: 
// Validating jsonInput1...
// Validating jsonInput2...
// Validating jsonInput3...
// $.element2: is missing and it is not optional
// [MyObject: element1=value1, element2=value2, element3=value3]
// [MyObject: element1=value1, element2=value2, element3=null]
// [MyObject: element1=value1, element2=null, element3=value3]

import java.util.List;

import org.codehaus.jackson.map.ObjectMapper;

import eu.vahlas.json.schema.JSONSchema;
import eu.vahlas.json.schema.JSONSchemaProvider;
import eu.vahlas.json.schema.impl.JacksonSchemaProvider;

public class Foo
{
  static String jsonSchema = 
    "{" + 
        "\"description\":\"Serialized MyObject Specification\"," + 
        "\"type\":[\"object\"]," + 
        "\"properties\":" + 
        "{" + 
            "\"element1\":{\"type\":\"string\"}," + 
            "\"element2\":{\"type\":\"string\",\"optional\":false}," + 
            "\"element3\":{\"type\":\"string\",\"optional\":true}" + 
        "}" + 
    "}";;

  static String jsonInput1 = "{\"element1\":\"value1\",\"element2\":\"value2\",\"element3\":\"value3\"}";
  static String jsonInput2 = "{\"element1\":\"value1\",\"element2\":\"value2\"}";
  static String jsonInput3 = "{\"element1\":\"value1\",\"element3\":\"value3\"}";

  public static void main(String[] args) throws Exception
  {
    ObjectMapper mapper = new ObjectMapper();
    JSONSchemaProvider schemaProvider = new JacksonSchemaProvider(mapper);
    JSONSchema schema = schemaProvider.getSchema(jsonSchema);

    System.out.println("Validating jsonInput1...");
    validateAndLogErrors(jsonInput1, schema);
    System.out.println("Validating jsonInput2...");
    validateAndLogErrors(jsonInput2, schema);
    System.out.println("Validating jsonInput3...");
    validateAndLogErrors(jsonInput3, schema);

    MyObject object1 = mapper.readValue(jsonInput1, MyObject.class);
    System.out.println(object1);
    MyObject object2 = mapper.readValue(jsonInput2, MyObject.class);
    System.out.println(object2);
    MyObject object3 = mapper.readValue(jsonInput3, MyObject.class);
    System.out.println(object3);
  }

  static void validateAndLogErrors(String jsonInput, JSONSchema schema)
  {
    List<String> errors = schema.validate(jsonInput);
    for (String error : errors)
    {
      System.out.println(error);
    }
  }
}

class MyObject
{
  String element1;
  String element2;
  String element3;

  void setElement1(String element1)
  {
    this.element1 = element1;
  }

  void setElement2(String element2)
  {
    this.element2 = element2;
  }

  void setElement3(String element3)
  {
    this.element3 = element3;
  }

  @Override
  public String toString()
  {
    return String.format(
        "[MyObject: element1=%s, element2=%s, element3=%s]",
        element1, element2, element3);
  }
}

这篇关于用Google的Gson严格分析JSON?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆