Esta es la contestación más exacta que te podemos dar, pero mírala pausadamente y valora si se adapta a tu trabajo.
Solución:
Tendría que cambiar algunas cosas para que esta validación funcione.
El controlador debe anotarse con @Validated
y @ValuesAllowed
debe anotar el parámetro de destino en el método.
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Validated
@RestController
@RequestMapping("/api/opportunity")
public class OpportunityController
@GetMapping("/vendors/list")
public String getVendorpage(
@RequestParam(required = false)
@ValuesAllowed(values =
"OpportunityCount",
"OpportunityPublishedCount",
"ApplicationCount",
"ApplicationsApprovedCount"
) String orderBy,
@RequestParam(required = false) String term,
@RequestParam(required = false) Integer page, @RequestParam(required = false) Integer size,
@RequestParam(required = false) String sortDir)
return "OK";
@ValuesAllowed
debería apuntar ElementType.PARAMETER
y en este caso ya no necesitas propName
propiedad porque Spring validará el parámetro deseado.
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ValuesAllowedValidator.class)
public @interface ValuesAllowed
String message() default "Field value should be from list of ";
Class>[] groups() default ;
Class extends Payload>[] payload() default ;
String[] values();
Validador:
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Arrays;
import java.util.List;
public class ValuesAllowedValidator implements ConstraintValidator
private List expectedValues;
private String returnMessage;
@Override
public void initialize(ValuesAllowed requiredIfChecked)
expectedValues = Arrays.asList(requiredIfChecked.values());
returnMessage = requiredIfChecked.message().concat(expectedValues.toString());
@Override
public boolean isValid(String testValue, ConstraintValidatorContext context)
boolean valid = expectedValues.contains(testValue);
if (!valid)
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(returnMessage)
.addConstraintViolation();
return valid;
Pero el código anterior devuelve HTTP 500 y contamina los registros con un seguimiento de pila feo. Para evitarlo, puede poner tales @ExceptionHandler
en el cuerpo del controlador (por lo que se limitará solo a este controlador) y obtendrá control sobre el estado HTTP:
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
String handleConstraintViolationException(ConstraintViolationException e)
return "Validation error: " + e.getMessage();
… o puede poner este método por separado @ControllerAdvice
class y tener aún más control sobre esta validación, como usarla en todos los controladores o solo en los deseados.
Caso 1: Si la anotación ValuesAllowed no se activa en absoluto, podría deberse a que no se anotó el controlador con @Validated.
@Validated
@ValuesAllowed(propName = "orderBy", values = "OpportunityCount", "OpportunityPublishedCount", "ApplicationCount", "ApplicationsApprovedCount" )
public class OpportunityController {
@GetMapping("/vendors/list")
public String getVendorpage(@RequestParam(required = false) String term,..
Caso 2: Si se activa y arroja un error, podría deberse a la BeanUtils.getProperty
no resolver las propiedades y lanzar excepciones.
Si las soluciones anteriores no funcionan, puede intentar mover la anotación al nivel del método y actualizar el Validador para usar la lista de valores válidos para el OrderBy
parámetro. Esto funcionó para mí. A continuación se muestra el código de muestra.
@RestController
@RequestMapping("/api/opportunity")
@Validated
public class OpportunityController {
@GetMapping("/vendors/list")
public String getVendorpage(@RequestParam(required = false) String term,
@RequestParam(required = false) Integer page, @RequestParam(required = false) Integer size,
@ValuesAllowed(propName = "orderBy", values = "OpportunityCount", "OpportunityPublishedCount", "ApplicationCount",
"ApplicationsApprovedCount" ) @RequestParam(required = false) String orderBy, @RequestParam(required = false) String sortDir)
return "success";
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ValuesAllowed.Validator.class )
public @interface ValuesAllowed
String message() default "Field value should be from list of ";
Class>[] groups() default ;
Class extends Payload>[] payload() default ;
String propName();
String[] values();
class Validator implements ConstraintValidator
private String propName;
private String message;
private List allowable;
@Override
public void initialize(ValuesAllowed requiredIfChecked)
this.propName = requiredIfChecked.propName();
this.message = requiredIfChecked.message();
this.allowable = Arrays.asList(requiredIfChecked.values());
public boolean isValid(String value, ConstraintValidatorContext context)
Aquí tienes las comentarios y calificaciones
Recuerda recomendar esta sección si te valió la pena.