2

I've got a simple REST resource which accepts a couple of query parameters. I'd like to validate one of these parameters, and came across ConstraintValidator for this purpose. The REST resource expects the query param territoryId to be a UUID, so I'd like to validate that it indeed is a valid UUID.

I've created an @IsValidUUID annotation, and a corresponding IsValidUUIDValidator (which is a ConstraintValidator). With what I have now, nothing gets validated and getSuggestions accepts anything I throw at it. So clearly I'm doing something wrong.

What am I doing wrong?

The REST resource now looks like this :

@Component
@Path("/search")
public class SearchResource extends AbstractResource {

    @GET
    @Path("/suggestions")
    @Produces(MediaType.APPLICATION_XML)
    public Response getSuggestions(
            @QueryParam("phrase") List<String> phrases, 
            @IsValidUUID @QueryParam("territoryId") String territoryId) {

        [...]

    }
}

IsValidUUID

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {IsValidUUIDValidator.class})
public @interface IsValidUUID {

    String message() default "Invalid UUID";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

}

IsValidUUIDValidator

public class IsValidUUIDValidator implements ConstraintValidator<IsValidUUID, String> {

    @Override
    public void initialize(IsValidUUID constraintAnnotation) {

    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null) {
            return true;
        }

        try {
            UUID.fromString(value);
            return true;

        } catch (Exception e) {
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate("The provided UUID is not valid")
                    .addConstraintViolation();

            return false;
        }

    }

}
sbrattla
  • 5,274
  • 3
  • 39
  • 63

1 Answers1

2

You need to set the supported targets on IsValidUUID, using the following annotation.

@SupportedValidationTarget(ValidationTarget.ANNOTATED_ELEMENT)

or

@SupportedValidationTarget(ValidationTarget.PARAMETERS)

Edit:

Sorry, I wasn't able to make it work either on a RequestParam directly. However, if you can, try creating a POJO that you can bind your request parameters to and annotate the binding field with your constraint instead. This worked for me.

public class MyModel {

    @IsValidUUID
    private String territoryId;

    public String getTerritoryId() {
        return territoryId;
    }
    public void setTerritoryId(String territoryId) {
        this.territoryId = territoryId;
    }

}

@GET
    @Path("/suggestions")
    @Produces(MediaType.APPLICATION_XML)
    public Response getSuggestions(
            @QueryParam("phrase") List<String> phrases, 
            @Valid @ModelAttribute MyModel myModel) {

        [...]

    }
praveenj
  • 349
  • 1
  • 2
  • 15
  • Thanks, it seems to work even witouth the @SupportedValidationTarget, but I was confused as the resource does not output the custom error message. It just outputs generic "Bad Request" JSON. – sbrattla May 23 '18 at 07:20
  • @sbrattla Please check the edit; I couldn't paste the code in comments. – praveenj May 23 '18 at 22:02