RESTサービスは、jsonスキーマに対してすべての着信jsonデータを検証する必要があります。 jsonスキーマはパブリックにアクセス可能であり、httpリクエストを介して取得できます。
Javaとjsonの間のマーシャリングとアンマーシャリングにjackson-framworkを使用しています。これまでのところ、jacksonを使用してスキーマに対してデータを検証する可能性はありませんでした。
JsonTools フレームワークも試してみましたが、これは明らかにこのような検証機能を思い付きます。しかし、残念ながら、検証を機能させることはできませんでした。 なぜJsonToolスキーマ検証が機能しないのですか?
そのような検証を行うにはどうすればよいですか?
RESTfulサービスへの着信jsonデータの検証を実施するためのベストプラクティスを検索しました。私の提案は、MessageBodyReader
メソッド内で検証を実行するreadFrom
を使用することです。以下に、簡単にするために一般的ではないメッセージ本文リーダーの例を示します。
また、jsonデータ検証を行うための最適なフレームワークを見つけることに興味がありました。私はjsonとJavaの間のマーシャリングとアンマーシャリングにjacksonフレームワーク(バージョン1.8.5)を使用しているため、このフレームワークがjsonデータ検証機能を提供するのは良かったでしょう。残念ながら、私はジャクソンでこれを行う可能性を見つけることができませんでした。最後に、 https://github.comで利用可能なjson-schema-validatorで動作するようにしました 。使用しているバージョンは2.1.7です
import Java.io.BufferedReader;
import Java.io.ByteArrayInputStream;
import Java.io.FileInputStream;
import Java.io.IOException;
import Java.io.InputStream;
import Java.io.InputStreamReader;
import Java.lang.annotation.Annotation;
import Java.lang.reflect.Type;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.Provider;
import org.codehaus.jackson.map.ObjectMapper;
import at.fhj.ase.dao.data.Address;
import at.fhj.ase.xmlvalidation.msbreader.MessageBodyReaderValidationException;
import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jackson.JsonLoader;
import com.github.fge.jsonschema.exceptions.ProcessingException;
import com.github.fge.jsonschema.main.JsonSchemaFactory;
import com.github.fge.jsonschema.main.JsonValidator;
import com.github.fge.jsonschema.report.ProcessingReport;
@Provider
@Consumes(MediaType.APPLICATION_JSON)
public class AddressJsonValidationReader implements MessageBodyReader<Address> {
private final String jsonSchemaFileAsString;
public AddressJsonValidationReader(@Context ServletContext servletContext) {
this.jsonSchemaFileAsString = servletContext
.getRealPath("/json/Address.json");
}
@Override
public boolean isReadable(Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
if (type == Address.class) {
return true;
}
return false;
}
@Override
public Address readFrom(Class<Address> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
throws IOException, WebApplicationException {
final String jsonData = getStringFromInputStream(entityStream);
System.out.println(jsonData);
InputStream isSchema = new FileInputStream(jsonSchemaFileAsString);
String jsonSchema = getStringFromInputStream(isSchema);
/*
* Perform JSON data validation against schema
*/
validateJsonData(jsonSchema, jsonData);
/*
* Convert stream to data entity
*/
ObjectMapper m = new ObjectMapper();
Address addr = m.readValue(stringToStream(jsonData), Address.class);
return addr;
}
/**
* Validate the given JSON data against the given JSON schema
*
* @param jsonSchema
* as String
* @param jsonData
* as String
* @throws MessageBodyReaderValidationException
* in case of an error during validation process
*/
private void validateJsonData(final String jsonSchema, final String jsonData)
throws MessageBodyReaderValidationException {
try {
final JsonNode d = JsonLoader.fromString(jsonData);
final JsonNode s = JsonLoader.fromString(jsonSchema);
final JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
JsonValidator v = factory.getValidator();
ProcessingReport report = v.validate(s, d);
System.out.println(report);
if (!report.toString().contains("success")) {
throw new MessageBodyReaderValidationException(
report.toString());
}
} catch (IOException e) {
throw new MessageBodyReaderValidationException(
"Failed to validate json data", e);
} catch (ProcessingException e) {
throw new MessageBodyReaderValidationException(
"Failed to validate json data", e);
}
}
/**
* Taken from <a href=
* "http://www.mkyong.com/Java/how-to-convert-inputstream-to-string-in-Java/"
* >www.mkyong.com</a>
*
* @param is
* {@link InputStream}
* @return Stream content as String
*/
private String getStringFromInputStream(InputStream is) {
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
String line;
try {
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
private InputStream stringToStream(final String str) throws UnsupportedEncodingException {
return new ByteArrayInputStream(str.getBytes("UTF-8"));
}
}
import com.github.fge.jsonschema.core.report.ProcessingReport;
import com.github.fge.jsonschema.main.JsonSchema;
import com.github.fge.jsonschema.main.JsonSchemaFactory;
import com.github.fge.jackson.JsonLoader;
import com.fasterxml.jackson.databind.JsonNode;
public class ValidationJSON {
public static void main(String[] arr){
String jsonData = "{\"name\": \"prem\"}";
String jsonSchema = ""; //Schema we can generate online using http://jsonschema.net/
final JsonNode data = JsonLoader.fromString(jsonData);
final JsonNode schema = JsonLoader.fromString(jsonSchema);
final JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
JsonValidator validator = factory.getValidator();
ProcessingReport report = validator.validate(schema, data);
System.out.println(report.isSuccess());
}
}