2010-07-02 14 views
16

मान लीजिए कि मैं जावा डेटा संरचनाओं में JSON पार्स करने के लिए Google की Gson लाइब्रेरी का उपयोग कर रहा हूं।Google के जीसन के साथ सख्त JSON पार्सिंग?

क्या जावा फ़ील्ड है जिसमें कोई संबंधित JSON नहीं है, तो अपवाद फेंकने का कोई आसान तरीका है? यही है, मैं जेएसओएन को जावा संरचना में सभी फ़ील्ड रखने की आवश्यकता है।

उत्तर

14

जीसन के पास JSON स्कीमा सत्यापन सुविधा नहीं है यह निर्दिष्ट करने के लिए कि कोई विशेष तत्व मौजूद होना चाहिए, और इसमें यह निर्दिष्ट करने का कोई तरीका नहीं है कि जावा सदस्य को पॉप्युलेट किया जाना चाहिए। ऐसी सुविधा उपलब्ध हो सकती है, जैसे @Required एनोटेशन के साथ। the Gson Issues List पर जाएं और एक वृद्धि अनुरोध में डाल दें।

जीसन के साथ, आप लागू कर सकते हैं कि निर्दिष्ट JSON तत्व कस्टम 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); 
    } 
} 

JSON Schema सत्यापन प्रदान करने वाले एपीआई का उपयोग करने के लिए एक बेहतर दृष्टिकोण हो सकता है। Jackson has at least a rudimentary implementation availableJSON Tools एक और परिपक्व होने लगता है।

जैक्सन के साथ यहां एक उदाहरण दिया गया है।

// 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); 
    } 
} 
+2

हालांकि अपने प्रस्तावित gson समाधान काम करता है जब आप एक और gson उदाहरण द्वारा प्रकार बनाने के लिए, यह काम नहीं करता एक ही संदर्भ का पुन: उपयोग करते समय। यह एक अनंत पाश का कारण बनता है। एक नया जीएसएन बनाकर आप अपने मूल जीसन के अन्य कॉन्फ़िगरेशन विकल्पों को खो देते हैं। – Moritz

0

आप रिकर्सिवली पुष्टि कर सकते हैं कि क्या json क्षेत्रों है कि कक्षा में घोषित नहीं हैं:

private static List<String> verifyElement(JsonObject element, Class klass) throws NoSuchFieldException, IllegalAccessException { 
    List<String> unknownFields = new ArrayList<>(); 
    Set<String> classFields = new HashSet<>(); 

    for (Field field : klass.getDeclaredFields()) { 
    if (!Modifier.isPublic(field.getModifiers())) { 
     throw new IllegalArgumentException("All fields must be public. Please correct this field :" + field); 
    } 
    } 

    for (Field field : klass.getFields()) { 
    classFields.add(field.getName()); 
    } 

    // Verify recursively that the class contains every 
    for (Map.Entry<String, JsonElement> entry : element.entrySet()) { 
    if (!classFields.contains(entry.getKey())) { 
     unknownFields.add(klass.getCanonicalName() + "::" + entry.getKey() + "\n"); 
    } else { 
     Field field = klass.getField(entry.getKey()); 
     Class fieldClass = field.getType(); 
     if (!fieldClass.isPrimitive() && entry.getValue().isJsonObject()) { 
     List<String> elementErrors = verifyElement(entry.getValue().getAsJsonObject(), fieldClass); 
     unknownFields.addAll(elementErrors); 
     } 
    } 
    } 
    return unknownFields; 

} 
संबंधित मुद्दे