用Google的Gson严格分析JSON? [英] Strict JSON parsing with Google's Gson?
问题描述
假设我使用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屋!