Adam
Adam

Reputation: 163

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...

Upvotes: 5

Views: 11090

Answers (1)

shazin
shazin

Reputation: 21883

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;
  }
}

Upvotes: 1

Related Questions