Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate validation annotation - validate that at least one field is not null

Is there a way to define a Hibernate validation rule using annotations as defined here, stating that at least one field shall be not null?

This would be a hypothetical example (@OneFieldMustBeNotNullConstraint does not really exist):

@Entity
@OneFieldMustBeNotNullConstraint(list={fieldA,fieldB})
public class Card {

    @Id
    @GeneratedValue
    private Integer card_id;

    @Column(nullable = true)
    private Long fieldA;

    @Column(nullable = true)
    private Long fieldB;

}

In the illustrated case, fieldA can be null or fieldB can be null, but not both.

One way would be to create my own validator, but I'd like to avoid if it already exists. Please share one validator if you have one already made... thanks!

like image 771
Resh32 Avatar asked Aug 31 '12 08:08

Resh32


People also ask

What is the use of @validated annotation?

The @Validated annotation is a class-level annotation that we can use to tell Spring to validate parameters that are passed into a method of the annotated class. We'll learn more about how to use it in the section about validating path variables and request parameters.

What is NotNull annotation?

@NotNull The @NotNull annotation is, actually, an explicit contract declaring that: A method should not return null. Variables (fields, local variables, and parameters) cannot hold a null value.

Which of the following annotations indicate a field that Cannot be a null?

Explanation: The @NotNull annotation, which indicates a field cannot be null .

What does @NotNull annotation mean in bean property?

@NotNull validates that the annotated property value is not null. @AssertTrue validates that the annotated property value is true. @Size validates that the annotated property value has a size between the attributes min and max; can be applied to String, Collection, Map, and array properties.


2 Answers

I finally wrote the whole validator:

import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;

import org.apache.commons.beanutils.PropertyUtils; 

@Target( { TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = CheckAtLeastOneNotNull.CheckAtLeastOneNotNullValidator.class)
@Documented
public @interface CheckAtLeastOneNotNull {
    
     String message() default "{com.xxx.constraints.checkatleastnotnull}";

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

     Class<? extends Payload>[] payload() default {};
        
     String[] fieldNames();
        
     public static class CheckAtLeastOneNotNullValidator implements ConstraintValidator<CheckAtLeastOneNotNull, Object> {
            
         private String[] fieldNames;

         public void initialize(CheckAtLeastOneNotNull constraintAnnotation) {
             this.fieldNames = constraintAnnotation.fieldNames();
         }

         public boolean isValid(Object object, ConstraintValidatorContext constraintContext) {

             if (object == null) {
                 return true;
             }
             try { 
                 for (String fieldName:fieldNames){
                     Object property = PropertyUtils.getProperty(object, fieldName);
                        
                     if (property != null) return true;
                 }
                 return false;
             } catch (Exception e) {
                 return false;
             }
         }
     }
}

Example of usage:

@Entity
@CheckAtLeastOneNotNull(fieldNames={"fieldA","fieldB"})
public class Reward {

    @Id
    @GeneratedValue
    private Integer id;

    private Integer fieldA;
    private Integer fieldB;

    [...] // accessors, other fields, etc.
}
like image 109
Resh32 Avatar answered Sep 19 '22 15:09

Resh32


Just write your own validator. Is't should be pretty simple: iterate over field names and get field values by using reflection.

Concept:

Collection<String> values = Arrays.asList(
    BeanUtils.getProperty(obj, fieldA),
    BeanUtils.getProperty(obj, fieldB),
);

return CollectionUtils.exists(values, PredicateUtils.notNullPredicate());

There I used methods from commons-beanutils and commons-collections.

like image 30
Slava Semushin Avatar answered Sep 19 '22 15:09

Slava Semushin