Spring Check Error Generation

I use JSR-303 for validation and Spring MVC 3. Verification is done manually through validator.validate(bean, errors)in the controller.

I annotated the nameclass property Foowith @NotNull. When the check failed, I noticed that Spring MVC generated the following error codes in the object Errors.

NotNull.form.foo.name
NotNull.name
NotNull.java.lang.String
NotNull

How the tag works <form:errors>, it will go through all the error codes and look for the default resource bundle until it returns a non-zero message. Is there a way to customize these error codes, or at least the order in which they are listed?

The reason is because I have a custom object ResourceBundlethat returns the default message received from the given message code if not one was found in the resource package text file. Since the tag works in the list of error codes, it first searches NotNull.form.foo.namein this example. Of course, the text file does not have this entry, so the custom ResourceBundle object will return the default message. The problem is that I already have the message defined in the text file for NotNull, but the tag will see it as it is.

If I could somehow create just one error code or reorder the error codes, this would work.

Any idea? Thank.

+3
source share
2 answers

, ...

-servlet.xml

<bean id="handlerAdapter" class="org.opensource.web.StandardAnnotationMethodHandlerAdapter">
</bean>

StandardAnnotationMethodHandlerAdapter.java

public class StandardAnnotationMethodHandlerAdapter extends AnnotationMethodHandlerAdapter    {
    @Override
    protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object target, String objectName) throws Exception {
    MyServletRequestDataBinder dataBinder = new MyServletRequestDataBinder(target, objectName);
    return dataBinder;
   }
}

MyServletRequestDataBinder.java

public class MyServletRequestDataBinder extends ServletRequestDataBinder {

private MessageCodesResolver messageCodesResolver = new MyMessageCodesResolver();

@Override
public void initBeanPropertyAccess() {
   super.initBeanPropertyAccess();
   BindingResult bindingResult = super.getBindingResult();
   if(bindingResult instanceof AbstractBindingResult) {
       ((AbstractBindingResult)bindingResult).setMessageCodesResolver(messageCodesResolver);
   }
}

@Override
public void initDirectFieldAccess() {
  super.initDirectFieldAccess();
  BindingResult bindingResult = super.getBindingResult();
  if(bindingResult instanceof AbstractBindingResult) {
     ((AbstractBindingResult)bindingResult).setMessageCodesResolver(messageCodesResolver);
    }
 }
}

MyMessageCodesResolver.java

public class MyMessageCodesResolver extends DefaultMessageCodesResolver {

public static final String NOT_NULL_ERROR_CODE = "NotNull";

@Override
public String[] resolveMessageCodes(String errorCode, String objectName, String field, Class fieldType) {
   if(NOT_NULL_ERROR_CODE.equalsIgnoreCase(errorCode)) {
       String notNullErrorCode = errorCode + CODE_SEPARATOR + objectName + CODE_SEPARATOR + field;
       //notNullErrorCode = postProcessMessageCode(notNullErrorCode);
       return new String[] {notNullErrorCode};
    }
      return super.resolveMessageCodes(errorCode, objectName, field, fieldType);
}   
}
+2

JSR-303 HibernateValidator bean Spring. , .

BeanValidator.java

import java.util.Locale;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;

public class BeanValidator implements org.springframework.validation.Validator, InitializingBean {

private static final Logger log = LoggerFactory.getLogger(BeanValidator.class.getName());

private Validator validator;

@Autowired
MessageSource messageSource;

@Override
public void afterPropertiesSet() throws Exception {
    ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
    validator = validatorFactory.usingContext().getValidator();
}

@Override
public boolean supports(Class clazz) {
    return true;
}

@Override
public void validate(Object target, Errors errors) {
    Set<ConstraintViolation<Object>> constraintViolations = validator.validate(target);
    for (ConstraintViolation<Object> constraintViolation : constraintViolations) {
        String propertyPath = constraintViolation.getPropertyPath().toString();
        String message;
        try {
            message = messageSource.getMessage(constraintViolation.getMessage(), new Object[]{}, Locale.getDefault());
        } catch (NoSuchMessageException e) {
            log.error(String.format("Could not interpolate message \"%s\" for validator. "
                    + e.getMessage(), constraintViolation.getMessage()), e);
            message = constraintViolation.getMessage();
        }
        errors.rejectValue(propertyPath, "", message);
    }
}
}

SpringMessageSourceMessageInterpolator.java

import javax.validation.MessageInterpolator;
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.NoSuchMessageException;

public class SpringMessageSourceMessageInterpolator extends ResourceBundleMessageInterpolator implements MessageInterpolator, MessageSourceAware, InitializingBean {

@Autowired
private MessageSource messageSource;

@Override
public String interpolate(String messageTemplate, Context context) {
    try {
        return messageSource.getMessage(messageTemplate, new Object[]{}, Locale.getDefault());
    } catch (NoSuchMessageException e) {
        return super.interpolate(messageTemplate, context);
    }
}

@Override
public String interpolate(String messageTemplate, Context context, Locale locale) {
    try {
        return messageSource.getMessage(messageTemplate, new Object[]{}, locale);
    } catch (NoSuchMessageException e) {
        return super.interpolate(messageTemplate, context, locale);
    }
}

@Override
public void setMessageSource(MessageSource messageSource) {
    this.messageSource = messageSource;
}

@Override
public void afterPropertiesSet() throws Exception {
    if (messageSource == null) {
        throw new IllegalStateException("MessageSource was not injected, could not initialize "
                + this.getClass().getSimpleName());
    }
}
}

applicationContext.xml

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource" p:basename="messages"/>

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
    <property name="messageInterpolator">
        <bean class="com.company.utils.spring.SpringMessageSourceMessageInterpolator" />
    </property>
</bean>

bean

@NotNull(message = "validation.mandatoryField")
private ClientGroup clientGroup;

@Controller
public class MyController {

    @Autowired
    private BeanValidator validator;

    @RequestMapping("/foo", method=RequestMethod.POST)
    public void processFoo(ModelAttribute("foo") Foo foo, BindingResult result, Model model) {
        //...
        validator.validate(foo, result);
    }
}
+2

Source: https://habr.com/ru/post/1775741/


All Articles