3

我正在尝试为org.springframework.validation.FieldError创建一个自定义编组器,这样我就可以避免在我的 JSON 响应中放入无关的和可能敏感的数据,其中包括MyCommandObject.errors.

但是我的 FieldError 编组器根本不起作用,这就是我在 BootStrap.groovy 中 init 方法下的内容。

    def fieldErrorMarshaller = {
        log.info("field error marshaller $it")
        def returnArray = [:]

        returnArray['field'] = it.field
        returnArray['message'] = it.message

        return returnArray
    }

    JSON.registerObjectMarshaller(FieldError, fieldErrorMarshaller)

我没有看到任何明确的错误或编组器日志记录。知道这里可能出了什么问题吗?

4

3 回答 3

5

Grails 注册了一个ValidationErrorsMarshaller处理所有错误的实例,因此您的 FieldError 编组器将永远不会被调用。

//convertAnother is not called for each error. That's the reason of your custom marshalled not been called.
for (Object o : errors.getAllErrors()) {
    if (o instanceof FieldError) {
        FieldError fe = (FieldError) o;
        writer.object();
        json.property("object", fe.getObjectName());
        json.property("field", fe.getField());
        json.property("rejected-value", fe.getRejectedValue());
        Locale locale = LocaleContextHolder.getLocale();
        if (applicationContext != null) {
            json.property("message", applicationContext.getMessage(fe, locale));
        }
        else {
        ...

查看ConvertersGrailsPlugin(插件的描述符)这是注册为 Spring Bean,因此您可以创建另一个 bean 并使用相同的名称注册,覆盖marshalObject()以满足您的需求(未测试,可能需要更多代码)。

class MyErrorsMarshaller implements ObjectMarshaller<JSON>, ApplicationContextAware {
    ApplicationContext applicationContext;

    public boolean supports(Object object) {
        return object instanceof Errors;
    }

    public void marshalObject(Object object, JSON json) throws ConverterException {
    ...
    }

}

资源.groovy

jsonErrorsMarshaller(MyErrorsMarshaller)

errorsJsonMarshallerRegisterer(ObjectMarshallerRegisterer) {
    marshaller = { MyErrorsMarshaller om -> }
    converterClass = grails.converters.JSON
}

ValidationErrorsMarshaller的参考。

ConvertersGrailsPlugin的参考。

于 2013-04-08T20:31:54.867 回答
3

对于任何好奇的人,这是我最终根据 Sérgio Michels 的回答在 Bootstrap.groovy 中编写的验证器

def validationErrorsMarshaller = {
    return it.getAllErrors().collect {
        if (it instanceof FieldError) {
            Locale locale = LocaleContextHolder.getLocale();
            def msg = messageSource.getMessage(it, locale)

            return [ field: it.getField(), message: msg ]
        }
    }
}

JSON.registerObjectMarshaller(ValidationErrors, validationErrorsMarshaller)

通过使用 messageSource,我能够从原始 Java 编组器中简化这一点,该消息源是通过添加def messageSource到 BootStrap 类中注入的。

于 2013-04-08T23:21:06.040 回答
0
//usage in grails controller
render domainObject.errors as JSON

//resources.groovy
jsonErrorsMarshaller(MyErrorsMarshaller)
errorsJsonMarshallerRegisterer(ObjectMarshallerRegisterer) {
    marshaller = { MyErrorsMarshaller om -> }
    converterClass = grails.converters.JSON
}

//grails.converters.JSON marshaller class
import grails.converters.JSON
import grails.validation.ValidationErrors
import org.codehaus.groovy.grails.web.converters.exceptions.ConverterException
import org.codehaus.groovy.grails.web.converters.marshaller.ObjectMarshaller
import org.codehaus.groovy.grails.web.json.JSONWriter
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
import org.springframework.context.i18n.LocaleContextHolder
import org.springframework.validation.Errors
import org.springframework.validation.FieldError
import org.springframework.validation.ObjectError


class MyErrorsMarshaller implements ObjectMarshaller<JSON>, ApplicationContextAware {
    ApplicationContext applicationContext;

    public boolean supports(Object object) {
        return object instanceof Errors;
    }

    public void marshalObject(Object object, JSON json) throws ConverterException {
        JSONWriter writer = json.getWriter();
        try {
            List<ObjectError> errors = ((ValidationErrors)object).getAllErrors()
            writer.object();
            writer.key("errors").array();
            Locale locale = LocaleContextHolder.getLocale();
            for(FieldError error : errors){
                FieldError fe = (FieldError) error;
                writer.object();
                writer.key("field").value(fe.getField()).key("message").value(applicationContext.getMessage(fe, locale));
                writer.endObject();
            }
            writer.endArray();
            writer.endObject();
        } catch (ConverterException ce) {
            throw ce;
        } catch (Exception e) {
            e.printStackTrace()
            throw new ConverterException( "Error converting Bean with class " + object.getClass().getName(), e);
        }
    }
}
于 2015-09-18T10:08:42.990 回答