I am in need to call validator.validateProperty() from my custom Validator and looking for a way to pass BOTH messageTemplate and interpolated message to ConstraintValidatorContext.
What i want to achieve is that if given property has a particular value than fire validation of another property.
MyCustomClassLevelValidator implements ConstraintValidator<Foo, Bar>{
#Autowired
private Validator validator
public boolean isValid(Bar bar,
ConstraintValidatorContext constraintValidatorContext){
if(bar.isSth()){
Set<ConstraintViolation<Bar>> somePropViolations = validator.validateProperty(bar, "someprop", Conditional.class);
for (ConstraintViolation<Bar> propertyViolation : somePropViolations) {
constraintValidatorContext.disableDefaultConstraintViolation();
constraintValidatorContext.buildConstraintViolationWithTemplate(propertyViolation.getMessageTemplate()).addNode(propertyViolation.getPropertyPath().toString())
.addConstraintViolation();
}
}
}
}
So the problem with my code is that when Bar is validated, constraint violations on "someprop" are not fully interpolated (constraint annotations attributes are not resolved)
class Bar{
...
#Digits(groups=Conditional.class, integer=4,fraction=0)
String someProp;
}
So when validating Bar like
Bar bar = new Bar();
bar.setSomeProp("99.9");
Set<ConstraintViolation<Bar>> constraintViolations = validator.validate(bar);
i see numeric value out of bounds (<{integer} digits>.<{fraction} digits> expected)
instead of
numeric value out of bounds (<4 digits>.<0 digits> expected)
Is there any way i put BOTH message Template and message text (interpolated version) on constraintValidatorContext ?
I don't think it's a good idea to call back to Validator from within a constraint validator implementation, as this might easily cause endless loops when validating the same object again, which hosts the current object.
Depending on how you invoke validation, you could you simply pass the Conditional group to the validation call:
if(bar.isSth()) {
Set<ConstraintViolation<Bar>> constraintViolations =
validator.validate(bar, Conditional.class);
}
else {
Set<ConstraintViolation<Bar>> constraintViolations =
validator.validate(bar);
}
Related
I've created the annotation I want to put on some fields of a class.
I want the annotation to check one of two or more fields:
#Documented
#Target({ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface OneOfFields {
}
For example - the class:
public class MyClassRq {
#OneOfFields
private String stringOne;
#OneOfFields
private String stringTwo;
}
If I create an HttpRequest with the body and set both fields, I want to get an exception, javax.validation exception is also possible.
What is the best way to write the validator?
Annotations can be processed in two phases:
At compile time (in this case through an Annotation Processor)
At runtime (in this case through reflection)
It depends on when you want to perform the check. Considering that it seems you want to check this at runtime (i.e. when you receive the object), then you could create a sample method that takes an object, scans all the fields of the object for the annotation #OneOfFields and if more than one is not null, then it throws an exception:
public static <T> T validate(T input) {
try {
int numberOfAnnotatedNonNull = 0;
for (Field field : input.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(OneOfFields.class) && (field.get(input) != null)) {
numberOfAnnotatedNonNull++;
if (numberOfAnnotatedNonNull > 1) {
throw new IllegalStateException("More than one field annotated by #OneOfFields has been set for this object");
}
}
}
return input;
} catch (IllegalAccessException e) {
throw new IllegalStateException("Could not validate input object", e);
}
}
Sample usage:
MyClassRq myClassRq = validate(yourInput);
If the above yourInput of type MyClassRq is valid, then it will simply return the same object. Else, it will throw an exception.
Some notes:
Here I'm throwing as soon as I find more than one field which is non null. You may of course create a cleaner error message (for example by collecting all the fields which are illegally set and returning their names)
Here I'm throwing a standard IllegalStateException but you can (you should probably) create your own custom exception
Don't forget to check that T input is not null (if it is, my code will crash).
This is a sample usage of the standard Java Reflect API, there are several ways of reaching the same purpose (I've just shown you the most "readable")
I have a Map that I receive from a browser redirection back from a third party to my Spring Controller as below -
#RequestMapping(value = "/capture", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public void capture(#RequestParam
final Map<String, String> response)
{
// TODO : perform validations first.
captureResponse(response);
}
Before using this payload, I need to do non-trivial validation, involving first checking for non-null values of a map, and then using those values in a checksum validation. So, I would like to validate my payload programmatically using the Spring Validator interface. However, I could not find any validator example for validating a Map.
For validating a Java Object, I understand how a Validator is invoked by passing the object and a BeanPropertyBindingResult to contain the errors to the Validator as below -
final Errors errors = new BeanPropertyBindingResult(object, objectName);
myValidator.validate(object, errors);
if (errors.hasErrors())
{
throw new MyWebserviceValidationException(errors);
}
For a Map, I can see that there is a MapBindingResult class that extends AbstractBindingResult. Should I simply use it, and pass my map in the Object object and in the validator cast it back to a Map? Also, how would the Validator method of supports(final Class<?> clazz) be implemented in my validator? Would it simply be like below code snippet where there can only be one validator supporting this generic class of HashMap? Somehow doesn't feel right. (Although this does not matter to me as I will be injecting my validator and use it directly and not through a validator registry, but still curious.)
#Override
public boolean supports(final Class<?> clazz)
{
return HashMap.class.equals(clazz);
}
Since, there is a MapBindingResult, I'm positive that Spring must be supporting Maps for validation, would like to know how. So would like to know if this is the way to go, or am I heading in the wrong direction and there is a better way of doing this.
Please note I would like to do this programmatically and not via annotations.
Just like I thought, Spring Validator org.springframework.validation.Validator does support validation of a Map. I tried it out myself, and it works!
I created a org.springframework.validation.MapBindingResult by passing in the map I need to validate and an identifier name for that map (for global/root-level error messages). This Errors object is passed in the validator, along with the map to be validated as shown in the snippet below.
final Errors errors = new MapBindingResult(responseMap, "responseMap");
myValidator.validate(responseMap, errors);
if (errors.hasErrors())
{
throw new MyWebserviceValidationException(errors);
}
The MapBindingResult extends AbstractBindingResult and overrides the method getActualFieldValue to give it's own implementation to get field from a map being validated.
private final Map<?, ?> target;
#Override
protected Object getActualFieldValue(String field) {
return this.target.get(field);
}
So, inside the Validator I was able to use all the useful utility methods provided in org.springframework.validation.ValidationUtils just like we use in a standard object bean validator. For example -
ValidationUtils.rejectIfEmpty(errors, "checksum", "field.required");
where "checksum" is a key in my map. Ah, the beauty of inheritance! :)
For the other non-trivial validations, I simply cast the Object to Map and wrote my custom validation code.
So the validator looks something like -
#Override
public boolean supports(final Class<?> clazz)
{
return HashMap.class.equals(clazz);
}
#Override
public void validate(final Object target, final Errors errors)
{
ValidationUtils.rejectIfEmpty(errors, "transactionId", "field.required");
ValidationUtils.rejectIfEmpty(errors, "checksum", "field.required");
final Map<String, String> response = (HashMap<String, String>) target;
// do custom validations with the map's attributes
// ....
// if validation fails, reject the whole map -
errors.reject("response.map.invalid");
}
Validate the parameters inside the map
For the validation of your Map following a specific mapping you will need a custom validator.
As this may be the usecase for some, validation of #RequestParam can be done using org.springframework.validation annotations, e.g.
#GetMapping(value = "/search")
public ResponseEntity<T> search(#RequestParam
Map<#NotBlank String,#NotBlank String> searchParams,
While #NotBlank checks if your string is not "",
#NotNull can validate non-null parameters which I guess was something you needed.
An alternative is to create your custom constraint annotation for a Map.
You can take a look the following link:
https://www.baeldung.com/spring-mvc-custom-validator
I am deserializing a JSON into a model with Jackson. Say I have the following model:
class Model {
private String fieldA;
private Optional<String> fieldB;
}
Here, fieldA is non-nullable. In the JSON, it can either be absent or filled in:
{
}
or
{
"fieldA": "value"
}
In Java, the not filled in-case results in a null value of the member fieldA.
My question: is there a way to reject a null value for fieldA? For the following input JSON, Jackson should throw an exception:
{
"fieldA": null
}
Note that I only want that behaviour for fieldA, and not fieldB, since fieldB is nullable (and hence it is wrapped around an Optional in the model).
I could also wrap fieldA in an Optional and add some bean validation there, but I would rather not change the model.
No Jackson does not provide validation API. You can just ignore null value by including #JsonInclude(Include.NON_NULL) to the class or use Bean Validation API which will validate and throw errors if conditions are not satisfied.
UPDATE:
For your comment answer, if anyhow you just wanted to skip fieldA value if it is null and let other allowed them than in setter method you could just manually check.
In your case:
public void setFieldA(String fieldA) {
if (fieldA != null) {
this.fieldA = fieldA;
}
}
I'm trying to define and use a custom security binding type called BasicRolesAllowed, as has been demonstrated in the Picketlink quickstarts here.
The only different between my type the ones in the quickstart, is that my annotation has to accept an array of strings (we want to secure methods using not just one but possibly combinations of roles), and thus my annotation is defined thus:
public #interface BasicRolesAllowed {
String[] value() default {};
}
Following the quickstart, I've tried to define how this decorator authenticates as such:
#Secures
#BasicRolesAllowed
public boolean doAdminCheck(Identity identity, IdentityManager identityManager, RelationshipManager relationshipManager) throws Exception {
/*
Sample usage of #BasicRolesAllowed is like:
#BasicRolesAllowed(value = RoleConstants.CREATE_USER)
TODO: need to get these from the #BasicRolesAllowed annotation instance/usage
*/
String[] requiredRoles = {};// get these from annotation
boolean isAuthorized = true;
for (String role : requiredRoles)
isAuthorized = isAuthorized && hasRole(relationshipManager, identity.getAccount(), getRole(identityManager, role));
return isAuthorized;
}
And as can be seen in the snippet, the trick part is:
String[] requiredRoles = {};// get these from annotation
How do I get the string constants passed to the annotation on the decorated method so I can use them in looking up roles?
Some Hints:
There's an answer to a similar question here, but the problem is that in that solution; one needs to know the name of the decorated function or class - which in my case is impossible given that the decorator will be used just about anywhere, and I don't know how to get these via the method shown in the Picketlink quickstart.
Also, the solution only shows how to obtain the value passed to an annotation expecting only 1 string - maybe I could try using values(), but the above limitation still stands in my way.
Thanks in advance to anyone who can help.
Thanks to #pedroigor over at #picketlink (freenode), the solution can be gleaned from an example of such a use-case in the picketlink quickstart here. In that file, a method getAnnotation() is defined, which has the signature:
private <T extends Annotation> T getAnnotation(InvocationContext invocationContext, Class<T> annotationType)
So, using this method, I'm able to introspect and obtain the values passed to my annotation as can be seen in my new implementation of the roles checking method here:
#Secures
#BasicRolesAllowed
public boolean hasBasicRolesCheck(InvocationContext invocationContext, Identity identity, IdentityManager identityManager, RelationshipManager relationshipManager) throws Exception {
BasicRolesAllowed basicRolesAllowed = getAnnotation(invocationContext,BasicRolesAllowed.class);
String[] requiredRoles = basicRolesAllowed.value();// get these from annotation
boolean isAuthorized = true;
for (String role : requiredRoles)
isAuthorized = isAuthorized && hasRole(relationshipManager, identity.getAccount(), getRole(identityManager, role));
return isAuthorized;
}
The essential modifications being:
I had to pass an instance of the invocation context InvocationContext invocationContext by adding this as a parameter to my method definition (CDI magic takes care of all else I hear).
I then obtain the annotation instance by calling:
BasicRolesAllowed basicRolesAllowed = getAnnotation(invocationContext,BasicRolesAllowed.class);
And then get the values/parameters passed to the annotation thus:
String[] requiredRoles = basicRolesAllowed.value();// get these from annotation
This solves my problem :-)
What happens if I annotate a constructor parameter using #JsonProperty but the Json doesn't specify that property. What value does the constructor get?
How do I differentiate between a property having a null value versus a property that is not present in the JSON?
Summarizing excellent answers by Programmer Bruce and StaxMan:
Missing properties referenced by the constructor are assigned a default value as defined by Java.
You can use setter methods to differentiate between properties that are implicitly or explicitly set. Setter methods are only invoked for properties with explicit values. Setter methods can keep track of whether a property was explicitly set using a boolean flag (e.g. isValueSet).
What happens if I annotate a constructor parameter using #JsonProperty but the Json doesn't specify that property. What value does the constructor get?
For questions such as this, I like to just write a sample program and see what happens.
Following is such a sample program.
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.ObjectMapper;
public class JacksonFoo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper();
// {"name":"Fred","id":42}
String jsonInput1 = "{\"name\":\"Fred\",\"id\":42}";
Bar bar1 = mapper.readValue(jsonInput1, Bar.class);
System.out.println(bar1);
// output:
// Bar: name=Fred, id=42
// {"name":"James"}
String jsonInput2 = "{\"name\":\"James\"}";
Bar bar2 = mapper.readValue(jsonInput2, Bar.class);
System.out.println(bar2);
// output:
// Bar: name=James, id=0
// {"id":7}
String jsonInput3 = "{\"id\":7}";
Bar bar3 = mapper.readValue(jsonInput3, Bar.class);
System.out.println(bar3);
// output:
// Bar: name=null, id=7
}
}
class Bar
{
private String name = "BLANK";
private int id = -1;
Bar(#JsonProperty("name") String n, #JsonProperty("id") int i)
{
name = n;
id = i;
}
#Override
public String toString()
{
return String.format("Bar: name=%s, id=%d", name, id);
}
}
The result is that the constructor is passed the default value for the data type.
How do I differentiate between a property having a null value versus a property that is not present in the JSON?
One simple approach would be to check for a default value post deserialization processing, since if the element were present in the JSON but had a null value, then the null value would be used to replace any default value given the corresponding Java field. For example:
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.map.ObjectMapper;
public class JacksonFooToo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper().setVisibility(JsonMethod.FIELD, Visibility.ANY);
// {"name":null,"id":99}
String jsonInput1 = "{\"name\":null,\"id\":99}";
BarToo barToo1 = mapper.readValue(jsonInput1, BarToo.class);
System.out.println(barToo1);
// output:
// BarToo: name=null, id=99
// {"id":99}
String jsonInput2 = "{\"id\":99}";
BarToo barToo2 = mapper.readValue(jsonInput2, BarToo.class);
System.out.println(barToo2);
// output:
// BarToo: name=BLANK, id=99
// Interrogate barToo1 and barToo2 for
// the current value of the name field.
// If it's null, then it was null in the JSON.
// If it's BLANK, then it was missing in the JSON.
}
}
class BarToo
{
String name = "BLANK";
int id = -1;
#Override
public String toString()
{
return String.format("BarToo: name=%s, id=%d", name, id);
}
}
Another approach would be to implement a custom deserializer that checks for the required JSON elements. And yet another approach would be to log an enhancement request with the Jackson project at http://jira.codehaus.org/browse/JACKSON
In addition to constructor behavior explained in #Programmer_Bruce's answer, one way to differentiate between null value and missing value is to define a setter: setter is only called with explicit null value.
Custom setter can then set a private boolean flag ("isValueSet" or whatever) if you want to keep track of values set.
Setters have precedence over fields, in case both field and setter exist, so you can "override" behavior this way as well.
I'm thinking of using something in the style of an Option class, where a Nothing object would tell me if there is such a value or not. Has anyone done something like this with Jackson (in Java, not Scala, et al)?
(My answer might be useful to some people finding this thread via google, even if it doesn't answer OPs question)
If you are dealing with primitive types which are omittable, and you do not want to use a setter like described in the other answers (for example if you want your field to be final), you can use box objects:
public class Foo {
private final int number;
public Foo(#JsonProperty Integer number) {
if (number == null) {
this.number = 42; // some default value
} else {
this.number = number;
}
}
}
this doesn't work if the JSON actually contains null, but it can be sufficient if you know it will only contain primitives or be absent
another option is to validate the object after deserialization either manually or via frameworks such java bean validation or, if you are using spring, the spring validation support.