Bean Validation etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Bean Validation etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

28 Ekim 2021 Perşembe

Bean Validation @Email Anotasyonu

Giriş
Şu satırı dahil ederiz.
import javax.validation.constraints.Email;
Kullanım
Örnek
Şöyle yaparız,
@Data
public class MyApiContract {
  ...
  @Email
  String emailAddress;
}
flags Alanı
Örnek
Normalde düzenli ifade küçük harf farkı gözetir. Bu olmasın istersek şöyle yaparız
@Data
public class MyApiContract {
  ...
  @Email(regexp = "[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,3}",
         flags = Pattern.Flag.CASE_INSENSITIVE)
  String emailAddress;
}
regexp Alanı
Örnek
Şöyle yaparız
@Data
public class MyApiContract {
  ...
  @Email(regexp = "[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,3}")
  String emailAddress;
}


26 Nisan 2021 Pazartesi

Bean Validation @Repeatable Anotasyonu

Giriş
Şu satırı dahil ederiz.
import java.lang.annotation.Repeatable;
Örnek
Elimizde şöyle bir kod olsun. Burada @Repeatable kullanılıyor. Bizim kendi kodumuz olan @ConditionalValidation anotasyonunun tekrar edebileceğini belirtiyor.  conditionalProperty alanı bean içindeki alan ismi, values bu alana atanabilecek değerler.
@Repeatable(ConditionalValidations.class)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {ConditionalValidator.class})
public @interface ConditionalValidation {

    String message() default "Field is required.";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

    String conditionalProperty();

    String[] values();

    String[] requiredProperties();
}
Böylece anotasyonumuzu artık şöyle kullanabiliriz
@ConditionalValidation(
        conditionalProperty = "kind", values = {"PRIVATE"},
        requiredProperties = {"firstName", "lastName"},
        message = "First and last name are required for private partners.")
@ConditionalValidation(
        conditionalProperty = "kind", values = {"BUSINESS"},
        requiredProperties = {"name"},
        message = "Name is required for a business partner.")
public class Partner {
  @NotEmpty
  private String id;
  @NotNull
  private PartnerKind kind;
  private String name;
  private String firstName;
  private String lastName;
}
Validator için şöyle yaparız. Önce Validator nesnemizde anotasyonda tanımlı bilgileri alırız. 
public class ConditionalValidator implements
ConstraintValidator<ConditionalValidation, Object> {

private String conditionalProperty;
  private String[] requiredProperties;
  private String message;
  private String[] values;

  @Override
  public void initialize(ConditionalValidation constraint) {
    conditionalProperty = constraint.conditionalProperty();
    requiredProperties = constraint.requiredProperties();
    message = constraint.message();
    values = constraint.values();
  }

  ...
}
Daha sonra şöyle yaparız
@Override
public boolean isValid(Object object, ConstraintValidatorContext context) {
  try {
    Object conditionalPropertyValue = BeanUtils.getProperty(object,
conditionalProperty);
    if (doConditionalValidation(conditionalPropertyValue)) {
      return validateRequiredProperties(object, context);
    }
  } catch (NoSuchMethodException|InvocationTargetException|IllegalAccessException ex) {
    return false;
  }
  return true;
}
private boolean validateRequiredProperties(Object object,
ConstraintValidatorContext context)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  boolean isValid = true;
  for (String property : requiredProperties) {
    Object requiredValue = BeanUtils.getProperty(object, property);
    boolean isPresent = requiredValue != null && !isEmpty(requiredValue);
    if (!isPresent) {
      isValid = false;
      context.disableDefaultConstraintViolation();
      context
        .buildConstraintViolationWithTemplate(message)
        .addPropertyNode(property)
        .addConstraintViolation();
    }
  }
  return isValid;
}
private boolean doConditionalValidation(Object actualValue) {
  return Arrays.asList(values).contains(actualValue);
}

24 Ocak 2019 Perşembe

Bean Validation API - JSR 303 + JSR 380

Giriş
JSR 303 ilk sürüm. JSR 380 tarafından geçersiz kılındı. JSR 380 yani Bean Validation 2.0 olarak ta bilinir

Maven
Örnek - Eski
Sadece Contraint'lerin yani anotasyonların bulunduğu jar için şöyle yaparız
<dependency>
  <groupId>javax.validation</groupId>
  <artifactId>validation-api</artifactId>
  <version>1.1.0.Final</version>
</dependency>
Ancak bu yetersiz, çünkü esasında bize bir gerçekleştirim (implementation) lazım. 

Örnek - Yeni Jakarta
Sadece Contraint'lerin yani anotasyonların bulunduğu jar için şöyle yaparız
<dependency>
  <groupId>jakarta.validation</groupId>
  <artifactId>jakarta.validation-api</artifactId>
  <version>3.0.0</version>
</dependency>
Ancak bu yetersiz, çünkü esasında bize bir gerçekleştirim (implementation) lazım. 

Hibernate
Açıklaması şöyle.
You can use oracle Validation API JSR-303, it is independent framework which can be use in web-based and none web-based applications, Hibernate provides implementation for that JSR-303. you can include the dependencies as follow in you pom.xml file
Hibernate kullanmak için şöyle yaparız
<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-validator</artifactId>
  <version>5.2.1.Final</version>
</dependency>
<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-validator-annotation-processor</artifactId>
  <version>5.2.1.Final</version>
</dependency>
Expression Language kullanmak için şöyle yaparız
<dependency>
   <groupId>javax.el</groupId>
   <artifactId>el-api</artifactId>
   <version>2.2</version>
</dependency>
Açıklaması şöyle
Expression Language is required in order to use the interpolation in the validation messages
Glassfish
Java SE ortamında şöyle yaparız
<dependency>
   <groupId>org.glassfish</groupId>
   <artifactId>javax.el</artifactId>
</dependency>
Anotasyon Listesi
Liste şöyle. Standarttaki bu anotasyonlar dışında kütüphaneler kendi anotasyonlarını da sağlıyorlar.
@AssertFalse
@AssertTrue
@DecimalMax(value=, inclusive=)
@DecimalMin(value=, inclusive=)
@Digits(integer=, fraction=)
@Email
@Future
@FutureOrPresent
@Max(value=)
@Min(value=)
@NotBlank
@NotEmpty
@NotNull
@Negative
@NegativeOrZero
@Null
@Past
@PastOrPresent
@Pattern(regex=, flags=)
@Positive
@PositiveOrZero
@Size(min=, max=)
Açıklaması şöyle
@Positive : Requires the value applicable to numeric values to be positive.

@PositiveOrZero : Requires the value applicable to numeric values to be positive or zero.

@Negative : Requires negative value applicable to numeric values.

@NegativeOrZero : Requires the value applicable to numeric values to be negative or zero.

@Past : Requires the value applicable to date fields to be a past date. It can also be applied to Date types coming in Java 8.

@PastOrPresent : Requires the value applicable to date fields to be a past date or present. It can also be applied to Date types coming in Java 8.

@Future : Requires the value applicable to date fields to be a future date. It can also be applied to Date types coming in Java 8.

@FutureOrPresent : Requires the value applicable to date fields to be a future date or now. It can also be applied to Date types coming in Java 8.
Bu anotasyonları kullanınca kod biraz kirleniyor ancak bence o kadar kötü değil. Açıklaması şöyle
I use JSR-303 validation because it keeps the code of my controllers cleaner. The downside is that I have to rely on “annotation magic” but I can live with it.
Kullanım
Normalde nesnenin kullanıldığı yeri @Valid anotasyonu ile işaretleriz. Mesela elimizde şöyle bir kod olsun
public class User {

  @NotBlank(message = "Name is mandatory")
  private String name;

  @NotBlank(message = "Email is mandatory")
  private String email;
  ...
}
SpringBoot ile şöyle yaparız
@RestController
public class UserController {
  @PostMapping("/users")
  ResponseEntity<String> addUser(@Valid @RequestBody User user) {
    ...
  }
}
Eğer hata varsa şu metod çağrılır. org.springframework.web.bind.MethodArgumentNotValidException sınıfı hataları içerir.
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map<String, String> handleValidationExceptions(MethodArgumentNotValidException ex) {

  Map<String, String> errors = new HashMap<>();
  ex.getBindingResult().getAllErrors().forEach((error) -> {
    String fieldName = ((FieldError) error).getField();
    String errorMessage = error.getDefaultMessage();
    errors.put(fieldName, errorMessage);
  });
  return errors;
}
Ancak eğer kullandığımız altyapı @Valid anotasyonunu otomatik işlemiyorsa, kodla yapmak gerekir.
1. Validation nesnesi aracılığıyla bir ValidatorFactory elde edilir.
2. ValidatorFactory aracılığıyla bir Validator elde edilir.
3. Validator belirtilen nesneyi doğrulayan bir bir sonuç döner.
Örnek
Şöyle yaparız
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<Foo>> violations = validator.validate(foo);
    
for (ConstraintViolation<Foo> violation : violations) {
  System.out.println(violation.getMessage());
}

16 Aralık 2018 Pazar

Bean Validation @Valid Anotasyonu

Giriş
Şu satırı dahil ederiz.
import javax.validation.Valid;
Complex Type Nedir
Composition ilişkisine sahip ve Bean Validation yapan iki sınıf varsa, owner tarafa da @Valid anotasyonu gerekir.

Örnek - Yanlış Kod
Elimizde şöyle bir kod olsun. Burada Address üye alanı Bean Validation anotasyonlarına sahip ancak @Valid ile işaretli olmadığı için null olmayan ancak boş bir Address nesnesi ile doğrulanırsa, exception fırlatılmaz.
public class User {

  @Id
  private String id;

  @NotEmpty
  private String name;

  @NotNull
  private Address address;
}
public class Address {

  @NotEmpty
  private String street;

  @NotEmpty
  private String city;

  @Size(min = 4, max = 6)
  private String postcode;
}
Örnek - Complex Type
List ile birleştirmek için şöyle yaparız.
public class UserAddressesForm {

  @NotEmpty
  private String firstName;

  @NotEmpty
  private String lastName;

  @Valid
  private List<AddressForm> addresses;
  ...
}

public class AddressForm {

  @NotEmpty
  private String customName;
  @NotEmpty
  private String city;
  @NotEmpty
  private String streetAn;
  @NotEmpty
  private String streetHn;
  @NotEmpty
  private String addressCountry;
  @NotEmpty
  private String postCode;
  ...
}
Örnek - Complex Type
Generic kullanarak şöyle yaparız.
public class ParentPojo<T> implements Serializable{
  @NotNull
  private String  cNumber;
  @NotNull
  private String  statusCode;
  @Valid 
  @NotNull 
  T child;
}
Örnek Complex Type
Hibernate @Email ile birleştirerek şöyle yaparız.
@Valid
private List<@Email String> emails = new ArrayList<>();
Örnek
Spring ile birleştirerek şöyle yaparız.
@RequestMapping(value = "/addUser", method = RequestMethod.POST)
public String addEmployee(@Valid @ModelAttribute("userFrom")User user,
  BindingResult result) {
  if(result.hasErrors()){
    return "User";
  }

  return "success";
}
Örnek
Elimizde bir alanı @NotNull olarak işaretli şöyle olan User nesnesi olsun.
@NotNull(message = "First Name cannot be null")
private String firstName;
Spring ile birleştirerek şöyle yaparız.
@RequestMapping(value = "/addUser", method = RequestMethod.POST)
public String addUser(@Valid User user, BindingResult result) {

  if (result.hasErrors()) {
    return "errorPage";
  } else {
    return "Done";
  }
}