As as anotações de validação do Jakarta Validation (Bean Validation) @notblank, @Email e @Size aplicadas nos parâmetros do construtor não impedem a criação do objeto em estado inconsistente automaticamente.
❌ Por que essas anotações não impedem a criação do objeto?
- As anotações de validação do Jakarta Validation (ex:
@NotBlank
,@Size
) não são verificadas automaticamente dentro do construtor. Elas só são aplicadas quando o Spring ou outro framework as invoca explicitamente com um mecanismo de validação. - No código apresentado, nada impede que o construtor receba valores inválidos, pois o Java puro não interpreta essas anotações.
🛠 Como evitar a criação de um objeto inconsistente?
Para garantir que a validação ocorra dentro do construtor, você pode fazer uma das seguintes abordagens:
1️⃣ Utilizar @Valid
em um DTO e converter para a entidade (Recomendado ✅)
Em um Controller do Spring Boot, a validação acontece automaticamente quando você usa @Valid
na entrada de um método.
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/autores")
public class AutorController {
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public void cadastrarAutor(@RequestBody @Valid AutorRequest autorRequest) {
Autor autor = autorRequest.toModel(); // Conversão segura após validação
System.out.println("Autor cadastrado: " + autor.getNome());
}
}
No DTO:
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
public class AutorRequest {
@NotBlank(message = "O nome é obrigatório")
private String nome;
@NotBlank(message = "O email é obrigatório")
@Email(message = "Formato de email inválido")
private String email;
@NotBlank(message = "A descrição é obrigatória")
@Size(max = 400, message = "A descrição não pode passar de 400 caracteres")
private String descricao;
public AutorRequest(String nome, String email, String descricao) {
this.nome = nome;
this.email = email;
this.descricao = descricao;
}
public Autor toModel() {
return new Autor(nome, email, descricao);
}
}
✅ Aqui a validação acontece antes do objeto Autor
ser criado!
2️⃣ Forçar a validação manualmente no construtor
Caso queira manter as anotações no construtor e garantir que a validação seja feita dentro da própria classe, você pode chamar um Validator
manualmente:
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import jakarta.validation.constraints.*;
import java.time.Instant;
import java.util.Set;
import jakarta.validation.ConstraintViolation;
public class Autor {
@NotBlank(message = "O nome é obrigatório")
private final String nome;
@NotBlank(message = "O email é obrigatório")
@Email(message = "Formato de email inválido")
private final String email;
@NotBlank(message = "A descrição é obrigatória")
@Size(max = 400, message = "A descrição não pode passar de 400 caracteres")
private final String descricao;
private final Instant instanteCriacao;
public Autor(String nome, String email, String descricao) {
this.nome = nome;
this.email = email;
this.descricao = descricao;
this.instanteCriacao = Instant.now();
validar(this); // Chama a validação manualmente
}
private void validar(Autor autor) {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<Autor>> violations = validator.validate(autor);
if (!violations.isEmpty()) {
throw new IllegalArgumentException(violations.iterator().next().getMessage());
}
}
}
🚨 Desvantagem: Essa abordagem é um pouco mais burocrática, pois exige a criação de um Validator
manualmente.
3️⃣ Usar @Validated
com Spring para validar no construtor
Caso você utilize o Spring, pode anotar a classe como @Validated
e injetar um Validator
:
import jakarta.validation.constraints.*;
import org.springframework.validation.annotation.Validated;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Instant;
@Component
@Validated
public class Autor {
private final String nome;
private final String email;
private final String descricao;
private final Instant instanteCriacao;
@Autowired
public Autor(
@NotBlank(message = "O nome é obrigatório") String nome,
@NotBlank(message = "O email é obrigatório") @Email(message = "Formato de email inválido") String email,
@NotBlank(message = "A descrição é obrigatória") @Size(max = 400, message = "A descrição não pode passar de 400 caracteres") String descricao
) {
this.nome = nome;
this.email = email;
this.descricao = descricao;
this.instanteCriacao = Instant.now();
}
}
✅ Essa abordagem usa o Spring para injetar automaticamente a validação.
🎯 Conclusão
🔴 As anotações @NotBlank
, @Email
, @Size
dentro do construtor NÃO impedem a criação do objeto automaticamente.
✅ Para evitar um estado inconsistente, é melhor validar os dados antes de criar a instância, usando um DTO (@Valid
no Controller).
✅ Se necessário, você pode chamar a validação manualmente dentro do construtor ou usar Spring para gerenciá-la com @Validated
.
Top comments (0)