I have a class with hibernate's validation annotation on some fields (such as @NotNull
and @Size(min = 4, max = 50)
, etc...)
public class MyClass {
Long id;
@NotEmpty
@Size(min = 4, max = 50)
String machineName;
@NotEmpty
@Size(min = 4, max = 50)
String humanName;
// Getters, setters, etc…
}
I also have a custom controller that acts as a JSON API, and a JSON deserializer that creates MyClass objects when API methods are called. In my custom controller I have a method to create a new object of that type:
@RequestMapping(method = RequestMethod.POST)
public long createMyObject(@RequestBody @Valid MyClass newObj) {
// Create the object in the database
return newObj.getId();
}
and another method that updates an existing object
@RequestMapping(method = RequestMethod.PUT)
public void updateMyObject(@RequestBody MyClass updatedObj) {
MyClass existingObj = // Get existing obj from DB by updatedObj.getId();
// Do some secondary validation, such as making sure that a specific
// field remains unchanged compared to the existing instance
if (existingObj.getMachineName() != null &&
!existingObj.getMachineName().equals(updatedObj.getMachineName())) {
throw new CannotChangeMachineNameException();
}
else {
updatedObj.setMachineName(existingObj.getMachineName());
}
// [HERE IS WHERE I WANT THE MAGIC TO HAPPEN]
// Save updatedObj to the database
}
While I can use @Valid
in createMyObject
, I cannot use it in updateMyObject
because our API implementation requires that machineName remains unchanged - users can call the API with a JSON object that either excludes machineName entirely or populate it with the same value that exists in the database.*
Before saving the updated object to the database I want to call the same validator that having the @Valid annotation would cause to be called. How can I find this validator and use it?
The Bean Validation API does not only allow to validate single class instances but also complete object graphs (cascaded validation). To do so, just annotate a field or property representing a reference to another object with @Valid as demonstrated in Example 2.5, “Cascaded validation”.
The @Valid annotation ensures the validation of the whole object. Importantly, it performs the validation of the whole object graph. However, this creates issues for scenarios needing only partial validation. On the other hand, we can use @Validated for group validation, including the above partial validation.
Nothing says you need to use @Valid in your controller methods only. Why not make a validation method that accepts a parameter you annotate as @Valid, then just return that same parameter.
Like this:
public Book validateBook(@Valid Book book) {
return book;
}
Looks like an alternative would be to use Hibernate's validation package. Here's it's documentation.
Basically, you get a Validator
from a ValidationFactory
, and then use the validator like this:
@Test
public void manufacturerIsNull() {
Car car = new Car(null, "DD-AB-123", 4);
Set<ConstraintViolation<Car>> constraintViolations =
validator.validate(car);
assertEquals(1, constraintViolations.size());
assertEquals("may not be null", constraintViolations.iterator().next().getMessage());
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With