Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Validation with MethodValidationPostProcessor

I'm trying to use Spring's MethodValidationPostProcessor for validation on my service layer. I had planned on creating a generic service interface and letting controllers inject the right service by type:

@Controller
@RequestMapping("/items")
public class ItemController {

  @Inject
  // inject a service for the domain type i am controller for
  private Service<Item> service;

  @RequestMapping(method = RequestMethod.POST, produces="application/json")
  public @ResponseBody Item create(@RequestBody Item item){
    return this.service.execute(item);
  }
}

I have a generic service definition and a simple implementation:

public interface Service<T> {
  public T execute(@Valid T item);
}

// example implementation:
@Named
@Validated
public class ItemService implements Service<Item>{

  @Override
  public Item execute(@Valid Item item) {
    return item;
  }
}

And then set up my application to include Springs MethodValidationPostProcessor to handle @Validated beans:

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {
    public static void main( String[] args ){
        SpringApplication application = new SpringApplication(Application.class);
        application.run(args);
    }

    @Bean
    public MethodValidationPostProcessor getMethodValidationPostProcessor(){
        MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
        processor.setValidator(this.validator());
        return processor;
    }

    @Bean
    public LocalValidatorFactoryBean validator(){
        return new LocalValidatorFactoryBean();
    }
}

This set up produces the following exception:

HV000162: The validated type org.commons.test.validation.ItemService does not specify the constructor/method: public abstract java.lang.Object org.commons.test.validation.Service.execute(java.lang.Object)

I'm pretty sure this is due the proxy that is being passed to the validator but I can't seem to find away around this. I'm sure this has to work (as in I'm sure the spring guys have thought of this) and I'm just missing something... Any help would be greatly appreciated.

UPDATE:

So I found that if Service<T> is an abstract class and not an interface everything works. As well, if I leave Service<T> as an interface an simply add another parameter to the method i.e: execute(String dummy, @Valid T value) this also cause the validation to work as expected. I'm starting to think this is a bug...

like image 798
Adam Avatar asked Nov 10 '22 01:11

Adam


1 Answers

Remove the @Valid from ItemService implementation. Usually it is only required at Interface level. Your code should look like the below one.

// example implementation:
@Named
@Validated
public class ItemService implements Service<Item>{

  @Override
  public Item execute(Item item) {
    return item;
  }
}
like image 142
shazin Avatar answered Nov 14 '22 23:11

shazin