#ConvertGroup based on parameter - java

I'm looking to implement bean validation with groups based on parameter. The idea is to have methods with signature like:
#POST
#Path("/id-{id}")
public SomeDTO updateProducer(#PathParam("id") String id, #MatrixParam("update") Class<ConvertGroupTarget> update, #Valid SomeDTO data);
This would serve as an equivalent of explicit ConvertGroup declaration, such as:
#POST
#Path("/id-{id}")
public SomeDTO updateProducer(#PathParam("id") String id, #Valid #ConvertGroup(from=Default.class, to=/*some class that implements ConvertGroupTarget*/) SomeDTO data);
Is this even possible at all? We're using Jersey with hibernate-validator.
EDIT: the purpose of this all. Say I want to validate beans based on some validation group for specific purposes. For example, some bean can have different rules that apply to creating and updating it. So the bean declaration looks like this:
class SomeDTO {
#NotNull(groups = {Create.class, Update.class})
private String id;
#NotNull(groups = {Create.class, Update.class})
private String name;
#NotNull(groups = Update.class)
private String something;
//getters, setters etc.
}
The classes Create and Update are just some marker classes/interfaces to provide typed declaration of the groups.
Now, say the API user is creating an entity and he does
POST /id-X123/;update=create. Here I just want to validate the ID and the name, but don't really care about the something property of the bean. But when API user wants to update the bean, the API should require that he specifies even the something property. This is normally done by converting the validation group - #ConvertGroup(from = Default.class, to = Create.class) for creating and #CovertGroup(from = Default.class, to = Update.class) for updating. However, I'm looking to skip the explicit declaration of a ConvertGroup annotation and do this programatically based on parameter.

ConvertGroup defines static group conversions so you won't have the ability to parameterize them. You define them once and for all.
I think what you want to do is to call the Validator with a group. I don't use Jersey so I don't know if they have a hook for it but what you should look for is this:
Set<ConstraintViolation<SomeDTO>> violations =
validator.validate(someDTO); // validate the default group
Set<ConstraintViolation<SomeDTO>> violations =
validator.validate(someDTO, Update.class); // validate the Update group

Related

Can Java Validator method validateProperty validate object with multiple fields inside?

As stated in the title, I'm using the Validator to validate fields based on their names like this:
mandatoryInputs.stream()
.map(x -> v.validateProperty(accountBenefitForm, x, AccountBenefitFormAdditionalInfo.class))
it works fine, but only for the simple fields like Strings that have their constraints in the accountBenefitForm for example:
#NotBlank(message = "Username can not be null.", groups = {AccountBenefitFormBasicInfo.class})
#Size(max = 255, message = "Username is too long (max size 255).")
private String username;
But it won't work for objects that have multiple fields inside them, like this one:
#Valid
private ContactData contactData;
where ContactData implementation looks like this:
#NotBlank(message = "You have to add e-mail address.", groups = {AccountBenefitFormAdditionalInfo.class})
#Email(message = "E-mail is not valid.", groups = {AccountBenefitFormAdditionalInfo.class})
#Size(max = 255, message = "E-mail is too long (max size 255).", groups = {AccountBenefitFormAdditionalInfo.class})
private String email;
#NotBlank(groups = {AccountBenefitFormAdditionalInfo.class})
private String phoneNumber;
Is there a way I can make this work or do I need to validate those more complex objects on their own?
You have basically two kinds of annotations that can be used for validations here: Spring annotations (#Validated) as well as the javax annotation (#Valid, #NotBlank) etc.
For Spring, you can luckily often skip the manual validation unless you have some custom constraints (e.g. if person lives in country ABC, they need to provide additional info). Annotating just the field is not enough if you don't cascade the validation from the outer class. This cascade can be done conveniently on method-level by annotating the method param with #Valid e.g.
void doSomething(#Valid ContactDataHolder contactDataHolder) { ... }
If you'd like to use validation in Spring, I would recommend to use the Spring Validator interface instead of the one from javax as it should give you the expected behavior for nesting. You might also decide to apply #Validated on the class level to save you from writing #Valid(ated) on the method level each time.
So I've managed to somewhat resolve my problem by using the Apache BVal. Heres the code to create a validator to use the validateProperty method with cascading validation enabled:
ValidatorFactory factory = Validation.byProvider(ApacheValidationProvider.class).configure().buildValidatorFactory();
CascadingPropertyValidator validator = factory.getValidator().unwrap(CascadingPropertyValidator.class);
validator.validateProperty(accountBenefitForm, x, true, Default.class, AccountBenefitFormAdditionalInfo.class))
where x is the string of field to validate, and if that field is annotated with #Valid, it will then validate the inside fields according to their own constraints.
Along the way I've also found out that you can just use the "normal" javax Validator and pass the field to validate as contactData.email which means validate email field of the contactData field of the object that u pass as first argument to the validateProperty method.
Edit:
BVal supports Bean Validation 1.1 (JSR 349) and not the 2.0 version(JSR 380), and since #NotBlank or #NotEmpty constrains are part of 2.0, it won't validate a field annotated with them. Here are the docs for the 1.1 , and 2.0

Builder pattern when retrieving entity from DB w/ spring boot reactor & mongo

I have the following bean that describes a mongo document, and that uses lombok:
#JsonDeserialize(builder = MyClass.MyClassBuilder.class)
#Builder(toBuilder = true)
#Value
public class MyClass {
private final String id;
#Default
private final String field = "defaultValue";
#JsonPOJOBuilder(withPrefix = "")
public static class MyClassBuilder {}
}
When deserializing {"id": "document"} with jackson, I end-up with a bean containing both id=document and field=defaultValue because it used the builder that provide a default value for the field.
Now what I want to do, is to have the defaultValue set for documents coming out of the database (coming from ReactiveMongoTemplate). But it seems to use the all args constructor even if I set it private (or some reflect black magic)
So the main question is: is it possible to tell spring to use the builder to build the bean when coming out of the database?
You are not going to be able to use your custom serialiser because when I go through the source code of MappingMongoConverter in spring mongodb (debugged it with a sample app) , I see only the following steps.
Once the value from db is available as org.bson.Document, MappingMongoConverter.java is looking to create your entity object.
First, it checks if you have any custom converters registered and if you have it, then use it. So one option is to use a custom converter registered.
If there is no custom converters registered, it goes and find the PersistenceConstructor and use it. I had an object with 3 constructors (no param, one param, and all param) and it chose my no param constructor.
However, if I annotate a constructor with #PersistenceConstructor, it is choosing that constructor. So could follow this approach but then you have to keep String field un-initialised and getting initialised differently in each constructor
MappingMongoConverter.java
conversions.hasCustomReadTarget
persistenceConstructor

How to use different validation rules on same entity in Hibernate?

Problem:
How to save object Account as nested object when only ID is needed without getting ConstraintValidator exception?
Problem is because i have set validation rules to class, but when i want to save sem entity as nested object i get exception that some property values are missing. So i would liek to have different validation rules when i want to persist object as a whole and when i want to use it only sa nested object (when only ID is needed).
public class Account {
private int id;
#NotNull
private String name;
#NotNull
private String lastName;
#NotNull
private String userName;
//getters&setters
If I include Account as nested object i just need ID to be able to use it as FK (account entity is already in DB), but because of #NotNull annotation i get Exception.
Is there a way to ignore those annotations from Account when trying to save object Shop or how to create different validation rules for Account to validate just soem other properties and not all?
public class Shop {
private int id;
private Account owner; // only ID is needed
Do you have any basic example? I dont understand those in documentation. I have already read documentation before posting here.
You want to look at Bean Validation groups where you can classify specific validations so they are only activated when that group is validated and ignored otherwise.
You can refer to the documentation here for details.
Taking an example from the documentation:
// This is just a stub interface used for tagging validation criteria
public interface DriverChecks {
}
// The model
public class Driver {
#Min(value = 18, message = "You must be 18", groups = DriverChecks.class)
private int age;
// other stuffs
}
A group is nothing more than a tag that allows you to enable/disable validations based on specific use cases at run-time. By not specifying the groups attribute on a bean validation annotation, it defaults to the Default group, which is what Bean Validation uses if a group-tag isn't specified at the time of validation.
That means the following holds true:
// Age won't be validated since we didn't specify DriverChecks.class
validator.validate( driver );
// Age will be validated here because we specify DriverChecks.class
validator.validate( driver, DriverChecks.class );
This works great when you're triggering the validation yourself inside your service methods because you can manually control which group checks are applicable based on that method's use case.
When it comes to integrating directly with Hibernate ORM's event listeners that can also trigger bean validation, group specifications become a bit harder as they must be specified based on the event-type raised by hibernate.
javax.persistence.validation.group.pre-persist
javax.persistence.validation.group.pre-update
javax.persistence.validation.group.pre-remove
For each of the above properties you can specify in the JPA properties supplied to Hibernate, you can list a comma delimited list of groups that are to be validated for each of those event types. This allows you to have varying checks during insert versus update versus removal.
If that isn't sufficient, there is always the fact that you can create your own constraint validator implementation and annotation to plug into Bean Validation and specify that at the class or property level.
I have often found this useful in cases where values from multiple fields must be validated as a cohesive unit to imply their validity as the normal field-by-field validations didn't suffice.

Best way to convert a JPA entity to REST representations using JAX-RS and Jackson

I'm looking for a way to export some JPA entities to a REST API, but instead of sending the whole entity every time I want to share just some specific fields depending of the entry point. Here's a small example:
Say we have an Author class with few fields:
#Entity
public class Author implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = SEQUENCE)
private Long id;
#NotNull
#Size(min = 1, message = "{required.field}")
private String name;
#NotNull
#Size(min = 1, message = "{required.field}")
private String country;
private LocalDate birthDate;
// getters and setters
}
And say we have this REST service (just two methods):
#Path("authors")
public class AuthorREST {
#Inject
private AuthorBC bc;
#GET
#Produces("application/json")
public List<Author> find(#QueryParam("q") String query) throws Exception {
List<Author> result;
if (Strings.isEmpty(query)) {
result = bc.findAll();
} else {
result = bc.find(query);
}
return result;
}
#GET
#Path("{id}")
#Produces("application/json")
public Author load(#PathParam("id") Long id) throws Exception {
Author result = bc.load(id);
if (result == null) {
throw new NotFoundException();
}
return result;
}
}
Now, this way, I'll always have the 4 fields when my API is called.
I understand that if I use Jackson I can set an #JsonIgnore to fields I want to ignore, and they will always be ignored.
But what if I want that, in some cases, my whole entity is returned by one service, and in other service (or other method in the same service), only 2 or 3 fields are returned?
Is there a way to do it?
#JsonView and mix-in
You already know you can use annotations such as #JsonIgnore and #JsonIgnoreProperties to make Jackson ignore some properties.
You also could check the #JsonView annotation. For some details on how to use #JsonView with JAX-RS, have a look here.
If modifying the JPA entities is not an option, consider mix-in annotations as described in this answer.
Data Transfer Object
Data Transfer Object (DTO) is a pattern that was created with a very well defined purpose: transfer data to remote interfaces, just like webservices. This pattern fits very well in REST APIs and using DTOs you'll have more flexibility in the long run. You can have tailored classes for your needs, once the REST resource representations don't need to have the same attributes as the persistence objects.
To avoid boilerplate code, you can use mapping frameworks such as MapStruct to map your REST API DTOs from/to your persistence objects.
For details on the benefits of using DTOs, check the following answers:
Why you should use DTOs in your REST API
Using tailored classes of request and response
To give better names to your DTOs, check the following answer:
Giving meaningful names to your DTOs
If you want to decouple the parsing from your JPA entities and return only certain attributes you can always use Mixins for this purpose.
http://www.cowtowncoder.com/blog/archives/2009/08/entry_305.html
https://github.com/FasterXML/jackson-docs/wiki/JacksonMixInAnnotations
One more thing. If you want things to be dynamic in one service to return one representation in another to return another representation. Your option is to write a custom JSON serializer!
Check this post for how to create a customer serializer:
How do I use a custom Serializer with Jackson?
For myself I found it quite suitable to use #JsonView annotation. So you can define fields to be rendered in specific view. You can find more info here http://wiki.fasterxml.com/JacksonJsonViews
I think you can write a custom MessageBodyWriter using Jersey framework and you can control the response payload the way you want. Here you have to write few lines of code in-order to manage the response payload. For more information please visit https://jersey.java.net/documentation/latest/message-body-workers.html#d0e6826
I would use Spring Data REST and then use the ApiModel annotation to hide the attributes you do not want exposed.

Is there any way to control the order of hibernate validator doing validation?

We have a requirement that every fields of the object must be validated in a special order.
For example, we have Person object like below:
public class Person {
#NotNull
private String firstName;
#NotNull
private String lastName;
// getter and setter
}
When I use the javax.validation.Validator to validate this object, we need to make sure that the firstName always be validated first and then lastName. Is there any way for hibernate validator archive that requirement?
You want to use group sequences. In particular you probably want to redefine the default group for your entity. See also Redefining the Default group for a class as defined by the Bean Validation specification .

Categories

Resources