我正在尝试为org.springframework.validation.FieldError创建一个自定义编组器,这样我就可以避免在我的JSON响应中添加无关且可能敏感的数据,其中包括MyCommandObject.errors
。
但是我的FieldError marshaller根本不工作,这就是我在initS方法下的BootStrap.groovy中所拥有的。
def fieldErrorMarshaller = {
log.info("field error marshaller $it")
def returnArray = [:]
returnArray['field'] = it.field
returnArray['message'] = it.message
return returnArray
}
JSON.registerObjectMarshaller(FieldError, fieldErrorMarshaller)
我没有看到任何明显的错误或marshaller日志记录。知道这里可能出现什么问题吗?
答案 0 :(得分:5)
Grails注册了一个处理所有错误的ValidationErrorsMarshaller
实例,因此你的FieldError marshaller永远不会被调用。
//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 {
...
}
}
<强> resources.groovy 强>
jsonErrorsMarshaller(MyErrorsMarshaller)
errorsJsonMarshallerRegisterer(ObjectMarshallerRegisterer) {
marshaller = { MyErrorsMarshaller om -> }
converterClass = grails.converters.JSON
}
答案 1 :(得分:3)
对于任何好奇的人来说,这是我最后根据SérgioMichels的回答在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 marshaller中简化这一点,这是通过将def messageSource
添加到BootStrap类来注入的。
答案 2 :(得分: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);
}
}
}