How to create Annotation in SpringBoot Java? [ENG/PT-BR]
Tags: springboot, java, beginners, tutorial
Published: 2023-11-20 19:01:11

## How to create an @Annotation in Java SpringBoot?

[Link to the post in Portuguese](#ancora1)

I was doing a code for registration and came across two different classes but that had the same purpose. Perform a filter in the database to know if that information was already present. With this need I searched the internet and saw that a possible solution would be to create an Annotation for this validation, this way would not have the repeated code snippet.

Now to the code: 

Initially you will need to create an interface, I will call **ChechValue** as in the file below.


``` java

@Documented
@Constraint(validatedBy = {ChechValueValidator.class})
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ChechValue {
    String message() default "default message";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    String fieldName();
    Class<?> domainClass();
}

```

To create the annotation you must import some information for it to be executed, first the **constraint** that will add to the spring bean the class that is being used for validation, according to the **Target** that is responsible for defining which elements we will obtain and finally the **Retention** that is responsible for defining how this annotation will be executed, in our case will be Runtime.

That done, we can create the standard fields of an annotation like:


```
message() // Responsible for having a standard message or receiving a message in case of error

groups() // Responsible for defining access groups

payload() // Responsible for receiving information, something similar to the body of a request

fieldName() // In our case is responsible for defining which field will be validated

domainClass() // Responsible for defining which class will be used as Base


```
>
It is worth mentioning that it is an important convention to create the implementation file with the same interface name by adding only the Validator at the end of the class.

That done, we will implement the validation. Initially we will implement the ConstraintValidator, in it we will define the interface that will be used to create the annotation and also the object that will receive, as in the code below.

``` java

public class ChechValueValidator implements ConstraintValidator<ChechValue, Object> {

    private String domainAttribute;
    private Class<?> class;
    @PersistenceContext
    private EntityManager manager;

    @Override
    public void initialize(UniqueValue constraintAnnotation) {
        domainAttribute = constraintAnnotation.fieldName();
        class = constraintAnnotation.domainClass();
    }

    @Override
    public boolean isValid(Object object, ConstraintValidatorContext context) {
        Query query = manager.createQuery(
            "Select 1 from " +
            klass.getName() +
            " Where " +
            domainAttribute +
            " =:value");

        query.setParameter("value", object);
        List<?> list = query.getResultList();

        Assert.state(list.size() <= 1, "More than one value was identified in the class " + class.getName());

        return list.isEmpty();
    }
}

```

As mentioned before we will have a validation if the value is already present, soon we will need to implement EntityManager, class that we will make the filter and the attribute that will be made the filter.

In the class isValid() validation will be done, in this case the filter will be performed in the database to know if there is more than one information with the same data.

Now we have the example of Annotation being used:

``` java
public class AuthorRequest {
    @NotNull(message = "is required")
    private final String name;
    @NotNull(message = "is required")
    @Email
    @ChechValue(domainClass = Author.class, fieldName = "email")
    private final String email;
    @NotNull(message = "is required")
    @NotEmpty
    private final String description;
}

```

Using this Annotation we stopped having several similar code snippets but at different points of the code, helping us in more code clarity and less repetition.

---

<a id="ancora1"></a>
## Como criar uma @Annotation em SpringBoot Java?

Estava fazendo um código para cadastro e me deparei com duas classes distintas porém que possuíam a mesma finalidade. Realizar um filtro no banco de dados para saber se aquela informação já era presente. Com essa necessidade procurei na internet e vi que uma possível solução seria criar uma annotation para essa validação, desta forma não teria o trecho de código repetido.  

Agora vamos ao código: 

Inicialmente você vai precisar criar uma Interface, irei chamar de ChechValue como no arquivo abaixo.

``` java

@Documented
@Constraint(validatedBy = {ChechValueValidator.class})
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ChechValue {
    String message() default "default message";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    String fieldName();
    Class<?> domainClass();
}

```

Para criar a anotação deve-se importar algumas informações para que ela seja executada, primeiro o Constraint que irá adicionar ao bean do spring a classe que está sendo utilizada para validação, segundo o Target que fica responsável por definir quais elementos iremos obter e por fim o Retention que é responsável por definir como será executada essa anotação, em nosso caso será Runtime.

Feito isso, podemos criar os campos padrões de uma anotação como:

```
message() // Responsável por ter uma mensagem padrão ou receber uma mensagem em caso de erro

groups() // Responsável por definir grupos de acesso

payload() // Responsável por receber informação, algo similar ao body de uma request

fieldName() // Em nosso caso é responsável por definir qual campo será validado

domainClass() // Responsável por definir qual classe será utilizada como Base

```

>
Vale ressaltar que é uma convenção importante criar o arquivo de implementação com o mesmo nome da interface adicionando apenas o Validator no fim da classe.

Feito isso, iremos implementar a validação. Inicialmente vamos implementar o ConstraintValidator, nele iremos definir a interface que será utilizada para criar a anotação e também a objeto que irá receber, como no código abaixo.

``` java

public class ChechValueValidator implements ConstraintValidator<ChechValue, Object> {

    private String domainAttribute;
    private Class<?> class;
    @PersistenceContext
    private EntityManager manager;

    @Override
    public void initialize(UniqueValue constraintAnnotation) {
        domainAttribute = constraintAnnotation.fieldName();
        class = constraintAnnotation.domainClass();
    }

    @Override
    public boolean isValid(Object object, ConstraintValidatorContext context) {
        Query query = manager.createQuery(
            "Select 1 from " +
            klass.getName() +
            " Where " +
            domainAttribute +
            " =:value");

        query.setParameter("value", object);
        List<?> list = query.getResultList();

        Assert.state(list.size() <= 1, "More than one value was identified in the class " + class.getName());

        return list.isEmpty();
    }
}

```

Como mencionado anteriormente iremos ter uma validação se o valor já é presente, logo precisaremos implementar o EntityManager, classe que iremos fazer o filtro e o atributo que será feito o filtro.

Na classe isValid() será feito a validação, nesse caso será realizado o filtro no banco de dados para sabermos se existe mais de uma informação com o mesmo dado.

Agora temos o exemplo da annotation sendo utilizada:

``` java

public class AuthorRequest {
    @NotNull(message = "is required")
    private final String name;
    @NotNull(message = "is required")
    @Email
    @ChechValue(domainClass = Author.class, fieldName = "email")
    private final String email;
    @NotNull(message = "is required")
    @NotEmpty
    private final String description;
}

```

Utilizando essa annotation deixamos de termos vários trechos de código parecidos porém em pontos diferentes do código, nos auxiliando em mais clareza de código e menos repetição.