java - 如何验证 REST 服务中的传入 JSON 数据?

标签 java json validation rest jsonschema

rest 服务需要根据 json 模式验证所有传入的 json 数据。 json 模式是公共(public)可访问的,可以通过 http 请求检索。

我正在使用 jackson-framwork 在 java 和 json 之间进行编码和解码。到目前为止,我找不到任何使用 jackson 验证架构数据的可能性。

我也试过 JsonTools显然提出了这样的验证功能的框架。但不幸的是,我无法让验证工作。 Why JsonTool schema validation isn't working?

我怎样才能进行这样的验证?

最佳答案

我搜索了将传入的 json 数据强制验证到 RESTful 服务的最佳实践。我的建议是使用 MessageBodyReaderreadFrom 方法中执行验证。下面有一个消息体阅读器示例,为了简单起见,它是非通用的。

我也有兴趣找到进行 json 数据验证的最佳框架。因为我使用 jackson 框架(版本 1.8.5)在 json 和 java 之间进行编码和解码,所以如果这个框架能够提供 json 数据验证功能会很好。不幸的是,我找不到与 jackson 一起做这件事的任何可能性。最后,我通过 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"));
    }

}

关于java - 如何验证 REST 服务中的传入 JSON 数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18154983/

相关文章:

php - jquery ajax发送json到php错误

ruby-on-rails - Rails 验证搜索参数

java - 当异常发生时,是否可以暂停我的 try block ,执行 catch block ,然后再次恢复我的 try block

jquery - 解析嵌套的 json 对象

javascript - 使用 Asp.Net MVC 和 KnockoutJS 处理日期

java - 如何在 Struts 2 中使用超链接传递 Action 名称?

laravel - Laravel 验证规则列表

java - Constants.java 中未定义的构造函数

java - 右键单击下拉菜单

java - 给定字符串中字符的第一个索引和最后一个索引之间的差异