Gson verfügt nicht über eine JSON-Schemaüberprüfungsfunktion, um anzugeben, dass ein bestimmtes Element vorhanden sein muss, und es gibt keine Möglichkeit anzugeben, dass ein Java-Member ausgefüllt werden muss. Es wäre vielleicht schön, eine solche Funktion verfügbar zu haben, beispielsweise mit einer @Required
Annotation. Gehe weiter zu the Gson Issues List und bringe eine Verbesserungsanfrage ein.
Mit Gson können Sie erzwingen, dass angegebene JSON-Elemente mit einem benutzerdefinierten Deserializer vorhanden sind.
// 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);
}
}
Ein bevorzugter Ansatz könnte die Verwendung einer API sein, die JSON Schema Validierung bietet. Jackson has at least a rudimentary implementation available. JSON Tools scheint einen reiferen zu haben.
Hier ist ein Beispiel mit 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);
}
}
Obwohl Ihre vorgeschlagenen Gson Lösung funktioniert, wenn Sie die Art von einem anderen Gson Instanz erstellen, funktioniert es nicht wenn derselbe Kontext wiederverwendet wird. Es verursacht eine Endlosschleife. Durch das Erstellen eines neuen Gons verlieren Sie andere Konfigurationsoptionen, die Ihr ursprünglicher Gson hatte. – Moritz