Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to integrate java bean validation api With Spring RestTemplate

Is there a way to integrate spring RestTemplate with JavaBean validation api. ?

I know there is a integration for spring controller. you can put @Valid on request body param and if Employee is not valid you will get MethodArgumentNotValidException exception . which you can handel in exception handler class.

  @PostMapping(value = "/add", produces = APPLICATION_JSON_VALUE)
  public ResponseEntity<String> addEmployee(
       @RequestBody @Valid Employee emp) {

    //...

  }

But what I want is similar way to validate response from spring restTemplate like when I call this way - I want to get same(or maybe other) exception from spring.

Employee emp = template.exchange("http:///someUrl", HttpMethod.GET, null);

I know I can inject validator like this and call validator.validate(..) on reponse.

  @Autowired
  private Validator validator;

But I do not want to do it each time manually.

like image 813
user1321466 Avatar asked Jul 26 '17 17:07

user1321466


People also ask

How do you add basic authentication to RestTemplate?

Now that everything is in place, the RestTemplate will be able to support the Basic Authentication scheme just by adding a BasicAuthorizationInterceptor: restTemplate. getInterceptors(). add( new BasicAuthorizationInterceptor("username", "password"));


1 Answers

You can subclass RestTemplate and validate the response just right after it was extracted from raw data.

Example:

public class ValidatableRestTemplate extends RestTemplate {

    private final Validator validator;

    public ValidatableRestTemplate(Validator validator) {
        this.validator = validator;
    }

    @Override
    protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor<T> responseExtractor) throws RestClientException {
        final T response = super.doExecute(url, method, requestCallback, responseExtractor);
        Object  body;
        if (response instanceof ResponseEntity<?>) {
            body = ((ResponseEntity) response) .getBody();
        } else {
            body = response;
        }
        final Set<ConstraintViolation<Object>> violations = validator.validate(body);
        if (violations.isEmpty()) {
            return response;
        }

        throw new ConstraintViolationException("Invalid response", violations);
    }
}

The usage then is quite simple, just define your subclass as RestTemplate bean.

Full sample:

@SpringBootApplication
public class So45333587Application {

    public static void main(String[] args) { SpringApplication.run(So45333587Application.class, args); }

    @Bean
    RestTemplate restTemplate(Validator validator) { return new ValidatableRestTemplate(validator); }

    public static class ValidatableRestTemplate extends RestTemplate {
        private final Validator validator;

        public ValidatableRestTemplate(Validator validator) { this.validator = validator; }

        @Override
        protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor<T> responseExtractor) throws RestClientException {
            final T response = super.doExecute(url, method, requestCallback, responseExtractor);
            Object  body;
            if (response instanceof ResponseEntity<?>) {
                body = ((ResponseEntity) response).getBody();
            } else {
                body = response;
            }
            final Set<ConstraintViolation<Object>> violations = validator.validate(body);
            if (violations.isEmpty()) {
                return response;
            }

            throw new ConstraintViolationException("Invalid response", violations);
        }
    }

    @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
    public static class Post {
        @Min(2) // change to '1' and constraint violation will disappear
        private Long   id;
        private Long   userId;
        private String title;
        private String body;

        @Override
        public String toString() { 
            return String.format("Post{id=%d, userId=%d, title='%s', body='%s'}", id, userId, title, body); 
        }
    }

    @Bean
    CommandLineRunner startup(RestTemplate restTemplate) {
        return args -> {
            final ResponseEntity<Post> entity = restTemplate.exchange("https://jsonplaceholder.typicode.com/posts/1", HttpMethod.GET, null, Post.class);
            System.out.println(entity.getBody());
        };
    }
}
like image 190
Bohdan Levchenko Avatar answered Oct 13 '22 02:10

Bohdan Levchenko