Java no Desenvolvimento Real: Anotações Comuns com Cenários de Uso Prático

No caminho para aprofundar o desenvolvimento em Java, as anotações (Annotations) são uma "ferramenta mágica" para aumentar a eficiência. Elas não são tão intuitivas quanto a lógica de negócios, mas simplificam silenciosamente as configurações, normalizam o código e reduzem o acoplamento, nos libertando de configurações XML complexas e código repetitivo.

No entanto, existem muitos tipos de anotações, e muitos iniciantes ficam no dilema de "aprender e esquecer por não usar". Hoje, focaremos nas anotações que aparecem com **alta frequência no desenvolvimento real**, categorizadas em cinco grandes cenários: "Spring Core, Desenvolvimento Web, Camada de Persistência de Dados, Ferramentas de Código e Básico do JDK", combinando com exemplos de negócios reais para explicar o uso em profundidade. Você pode copiar diretamente para o seu projeto após a leitura!

I. Anotações Core do Spring: A Base da Inversão de Controle e Injeção de Dependência

O núcleo do framework Spring é a IOC (Inversão de Controle) e AOP (Programação Orientada a Aspectos), e as anotações são justamente o veículo central para realizar essas características. No desenvolvimento diário, quase toda classe que você escreve pode usá-las.

1. @Component e Suas Derivações: Entregar a Classe para o Gerenciamento do Spring

Função: Marcar uma classe como um "Bean gerenciado pelo Spring", permitindo que o Spring crie automaticamente a instância e a coloque no contêiner, sem precisar criar objetos manualmente com new. Este é o pré-requisito para a injeção de dependência.

Anotações Derivadas (semântica mais clara, mesma funcionalidade):

  • @Controller: Usado na camada Controller (receber requisições, retornar respostas), deixando claro que a responsabilidade da classe é tratar requisições do front-end.
  • @Service: Usado na camada Service (processamento da lógica de negócios), identificando que esta é a classe de negócios central, facilitando o aprimoramento posterior do aspecto AOP (como transações, logs).
  • @Repository: Usado na camada Dao (acesso a dados), originalmente em combinação com Spring Data, agora mais frequentemente substituído pelo @Mapper do MyBatis, mas semanticamente ainda é recomendado mantê-lo.

Exemplo Prático:

// Camada Controller: Recebe a requisição do usuário
@Controller
@RequestMapping("/customer")
public class CustomerController {
    // Injeção de dependência do objeto da camada Service
    @Autowired
    private CustomerService customerService;
    
    // Trata a requisição para buscar um cliente
    @GetMapping("/{identifier}")
    @ResponseBody
    public Customer retrieveCustomer(@PathVariable Long identifier) {
        return customerService.fetchCustomerById(identifier);
    }
}

// Camada Service: Lida com a lógica de negócios
@Service
public class CustomerServiceImpl implements CustomerService {
    @Autowired
    private CustomerRepository customerRepository;
    
    // Anotação de transação: Garante a atomicidade do negócio
    @Transactional
    @Override
    public Customer fetchCustomerById(Long identifier) {
        // Lógica de negócios
        return customerRepository.findById(identifier);
    }
}

2. @Autowired e @Resource: O "Duo" da Injeção de Dependência

Função: Obter um Bean do contêiner do Spring e injetá-lo na classe atual, evitando chamar getBean() manualmente. É a chave para o desacoplamento.

Diferença Core (essencial distinguir no desenvolvimento):

  • @Autowired: Anotação nativa do Spring, injeta por "tipo (byType)". Se houver múltiplos Beans do mesmo tipo, é necessário usar @Qualifier para especificar o nome do Bean.
  • @Resource: Anotação nativa do JDK (javax.annotation.Resource), por padrão injeta por "nome (byName)". Se o nome não corresponder, então casa por tipo, sem necessidade de anotações adicionais.

Exemplo Prático de Atenção:

@Service
public class CheckoutService {
    // Cenário 1: Apenas um Bean do mesmo tipo, usa @Autowired diretamente
    @Autowired
    private OrderProcessor orderProcessor;
    
    // Cenário 2: Múltiplos Beans do mesmo tipo (ex: duas implementações de PaymentGateway), é necessário especificar o nome
    @Autowired
    @Qualifier("stripeGateway") // Corresponde ao nome do Bean (padrão: nome da classe com a primeira letra minúscula)
    private PaymentGateway creditCardGateway;
    
    // Cenário 3: Usar @Resource é mais conciso, especificando o nome diretamente
    @Resource(name = "paypalGateway")
    private PaymentGateway digitalWalletGateway;
}

3. @Transacitonal: Gerencie Transações com Uma Única Linha de Código

Função: Adicionar suporte de transação a um método, garantindo o princípio de "tudo ou nada". É a anotação core para resolver problemas de consistência de dados (por exemplo, a criação de um pedido e a dedução do estoque devem ser concluídas com sucesso juntas).

Atributos Chave (comumente usados no desenvolvimento):

  • rollbackFor: Especifica quais exceções desencadeiam um rollback (por padrão, apenas exceções de runtime fazem rollback). Deve ser configurado, caso contrário, exceções não-runtime (como IOException) não causarão rollback.
  • propagation: Comportamento de propagação da transação, como REQUIRED (padrão, cria uma nova se não houver transação, junta se houver), REQUIRES_NEW (força a criação de uma nova transação).

Exemplo Prático:

@Service
public class CheckoutServiceImpl implements CheckoutService {
    @Autowired
    private OrderDao orderDao;
    @Autowired
    private InventoryDao inventoryDao;
    
    // Negócio core: Criar pedido + deduzir estoque, deve ser atômico
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    @Override
    public void placeOrder(Order order) {
        // 1. Criar o pedido
        orderDao.insert(order);
        // 2. Deduzir o estoque (se uma exceção for lançada aqui, a criação do pedido fará rollback)
        inventoryDao.reduceStock(order.getProductId(), order.getQuantity());
    }
}

II. Anotações de Desenvolvimento Web: "Atalhos" para o Desenvolvimento de APIs

Seja com Spring MVC ou Spring Boot, o desenvolvimento de APIs não pode prescindir dessas anotações. Elas definem o método da requisição, o mapeamento de parâmetros e o formato da resposta, sendo a ponte de interação entre front-end e back-end.

1. @RequestMapping e Suas Derivações: Localizando o Endereço da API

Função: Mapear requisições HTTP para métodos do Controller, especificando o caminho de acesso e o método da requisição da API.

Anotações Derivadas (substituem @RequestMapping, mais concisas):

  • @GetMapping: Corresponde a requisições GET, usado para buscar dados (ex: buscar usuário, buscar pedidos).
  • @PostMapping: Corresponde a requisições POST, usado para submeter dados (ex: criar usuário, fazer pedido).
  • @PutMapping: Corresponde a requisições PUT, usado para atualizar dados (atualização completa).
  • @DeleteMapping: Corresponde a requisições DELETE, usado para deletar dados.

Exemplo Prático:

@RestController // = @Controller + @ResponseBody, retorna formato JSON
@RequestMapping("/items") // Prefixo de caminho a nível de classe
public class ItemController {
    // Busca um item: GET /items/123
    @GetMapping("/{itemId}")
    public Item getItem(@PathVariable Long itemId) {
        // Lógica de negócios
    }
    
    // Adiciona um item: POST /items
    @PostMapping
    public Result createItem(@RequestBody Item item) { // @RequestBody recebe parâmetros JSON
        // Lógica de negócios
        return Result.success();
    }
    
    // Atualiza um item: PUT /items/123
    @PutMapping("/{itemId}")
    public Result modifyItem(@PathVariable Long itemId, @RequestBody Item item) {
        // Lógica de negócios
        return Result.success();
    }
    
    // Deleta um item: DELETE /items/123
    @DeleteMapping("/{itemId}")
    public Result removeItem(@PathVariable Long itemId) {
        // Lógica de negócios
        return Result.success();
    }
}

2. Anotações de Mapeamento de Parâmetros: @PathVariable, @RequestBody, @RequestParam

Função: "Pegar" os parâmetros da requisição HTTP e vinculá-los aos parâmetros formais do método, sendo o core para as APIs receberem dados.

  • @PathVariable: Obtém parâmetros do caminho da URL (ex: o id em /order/{id}), comumente usado em APIs RESTful.
  • @RequestBody: Obtém dados JSON do corpo da requisição, usado para receber objetos complexos (como a combinação de username, senha, telefone ao criar um novo usuário).
  • @RequestParam: Obtém parâmetros de consulta da URL (ex: /order?status=1&page=1), pode especificar se é obrigatório ou o valor padrão.

Exemplo Prático:

@GetMapping("/orders")
// Consulta paginada de pedidos: /orders?state=active&pageNum=1&pageSize=20
public PageResult<order> fetchOrders(
    @RequestParam(required = true) String state, // Parâmetro obrigatório
    @RequestParam(defaultValue = "1") Integer pageNum, // Não obrigatório, valor padrão 1
    @RequestParam(defaultValue = "20") Integer pageSize) { // Não obrigatório, valor padrão 20
    return orderService.getOrders(state, pageNum, pageSize);
}</order>

III. Anotações da Camada de Persistência: "Simplificadores" da Interação com o Banco de Dados

Seja MyBatis ou Spring Data JPA, essas anotações podem substituir configurações XML complexas, tornando as operações de banco de dados mais concisas.

1. Anotações Core do MyBatis: @Mapper, @Select, @Insert, etc.

Função: Desenvolvimento baseado em anotações do MyBatis, sem a necessidade de escrever arquivos Mapper.xml, definindo consultas SQL diretamente nos métodos da interface.

Anotações Comuns:

  • @Mapper: Marca a interface Dao para que o MyBatis escaneie e gere um objeto proxy, sem precisar adicionar @MapperScan na classe principal.
  • @Select/@Insert/@Update/@Delete: Escreve instruções SQL diretamente na anotação, adequado para consultas simples.
  • @Param: Especifica um apelido para o parâmetro do método, facilitando sua referência na consulta SQL (deve ser usado quando houver mais de um parâmetro).

Exemplo Prático:

// Interface Dao
@Mapper
public interface UserRepository {
    // Consulta simples: busca usuário por ID
    @Select("SELECT id, name, email FROM users WHERE id = #{userId}")
    User findById(Long userId);
    
    // Consulta com múltiplos parâmetros: busca por nome e email
    @Select("SELECT id, name, email FROM users WHERE name = #{userName} AND email = #{userEmail}")
    User findByNameAndEmail(@Param("userName") String name, @Param("userEmail") String email);
    
    // Inserir um novo usuário
    @Insert("INSERT INTO users(name, email, registration_date) VALUES(#{name}, #{email}, NOW())")
    @Options(useGeneratedKeys = true, keyProperty = "id") // Retorna a chave primária auto-incrementada
    void insert(User user);
}

2. Anotações do Spring Data JPA: @Entity, @Id, @Column

Função: JPA é uma especificação de framework ORM. Através de anotações, mapeia a relação entre classes Java e tabelas do banco de dados, permitindo o desenvolvimento com "zero SQL".

Anotações Core:

  • @Entity: Marca uma classe como "classe de entidade", correspondendo a uma tabela no banco de dados.
  • @Id: Especifica o campo de chave primária da classe, correspondendo à chave primária da tabela.
  • @GeneratedValue: Especifica a estratégia de geração da chave primária (ex: auto-incremento, UUID).
  • @Column: Especifica a relação de mapeamento entre o campo e a coluna da tabela (ex: nome da coluna, comprimento, se pode ser nulo).

Exemplo Prático:

// Classe de entidade: corresponde à tabela 'accounts' do banco de dados
@Entity
@Table(name = "accounts") // Pode ser omitido se o nome da classe for igual ao nome da tabela
public class Account {
    // Chave primária: estratégia de auto-incremento
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    // Nome de usuário: coluna 'username', não nulo, comprimento 100
    @Column(name = "username", nullable = false, length = 100)
    private String username;
    
    // Email: coluna 'email', único
    @Column(unique = true)
    private String email;
    
    // Data de criação: coluna 'created_at', timestamp gerado automaticamente
    @Column(name = "created_at")
    private LocalDateTime createdAt;
    
    // getters/setters
}

IV. Anotações de Ferramentas de Código: "Assistentes" para Melhorar a Qualidade do Código

Essas anotações não envolvem lógica de negócios, mas podem normalizar o código e reduzir código repetitivo, sendo um "entendimento tácito" no desenvolvimento em equipe.

1. Anotações do Lombok: Eliminando o "Código de Modelo"

Função: Lombok é uma "ferramenta mágica" no desenvolvimento Java. Através de anotações, gera automaticamente getters/setters, métodos construtores, toString e outro código repetitivo, tornando as classes mais concisas.

Anotações de Alta Frequência:

  • @Data: Anotação composta, inclui @Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor, a mais usada no desenvolvimento.
  • @NoArgsConstructor: Gera um método construtor sem parâmetros (obrigatório para JPA).
  • @AllArgsConstructor: Gera um método construtor com todos os parâmetros.
  • @Slf4j: Gera automaticamente o objeto de log log, sem precisar declarar manualmente private static final Logger log = LoggerFactory.getLogger(XXX.class);.

Exemplo Prático:

// Com as anotações do Lombok, não é necessário escrever getters/setters, toString, etc.
@Data
@NoArgsConstructor
@AllArgsConstructor
@Slf4j
public class Invoice {
    private Long invoiceId;
    private String referenceNumber;
    private Long clientId;
    private BigDecimal totalAmount;
    
    public void processInvoice() {
        // Usa o objeto 'log' diretamente para registrar informações
        log.info("Iniciando processamento para a fatura {}", referenceNumber);
        // Lógica de negócios
    }
}

2. Anotações de Validação: @NotNull, @NotBlank, @Valid

Função: Validação de parâmetros (ex: nome de usuário não pode ser vindo vazio do front-end, formato do telefone está correto), substituindo julgamentos manuais if-else, melhorando a legibilidade do código.

Anotações Comuns (pacote javax.validation.constraints):

  • @NotBlank: A string não pode ser nula e não pode ser composta apenas por espaços (aplicável para username, senha).
  • @NotNull: O objeto não pode ser nulo (aplicável para tipos numéricos, como idade, id).
  • @Pattern: A string corresponde a uma expressão regular (ex: telefone, email).
  • @Valid: Dispara a validação do parâmetro, colocado antes do parâmetro do método.

Exemplo Prático:

// DTO para receber parâmetros do front-end
@Data
public class NewUserDTO {
    @NotBlank(message = "O nome de usuário não pode estar em branco")
    private String username;
    
    @NotBlank(message = "A senha não pode estar em branco")
    @Size(min = 8, max = 24, message = "A senha deve ter entre 8 e 24 caracteres")
    private String password;
    
    @Pattern(regexp = "^\\+?[0-9]{7,15}$", message = "Formato de telefone inválido")
    private String phone;
    
    @NotNull(message = "A idade não pode ser nula")
    @Min(value = 18, message = "A idade mínima é 18 anos")
    private Integer age;
}

// Camada Controller: Dispara a validação
@PostMapping("/register")
public Result registerUser(@Valid @RequestBody NewUserDTO newUserDTO, Errors validationErrors) {
    // Falha na validação, retorna a mensagem de erro
    if (validationErrors.hasErrors()) {
        String errorMessage = validationErrors.getFieldError().getDefaultMessage();
        return Result.fail(errorMessage);
    }
    // Validação passou, executa a lógica de negócios
    userService.createAccount(newUserDTO);
    return Result.success();
}

V. Anotações Básicas do JDK: "Ferramentas Pequenas" Nativas do Java

Essas são anotações nativas do Java. Embora simples, aparecem com frequência no desenvolvimento, especialmente em cenários de manutenção de código e serialização.

  • @Override: Marca que um método sobrescreve um método da classe pai. Se houver erro no nome do método (ex: escrever toStr em vez de toString), o compilador lançará um erro, evitando erros de nível baixo.
  • @Deprecated: Marca um método ou classe como obsoleto, alertando os desenvolvedores para não utilizá-lo, e pode sugerir a alternativa através da documentação @deprecated.
  • @SuppressWarnings: Suprime avisos do compilador (ex: "variável não usada", avisos "unchecked"). Use com cautela, para evitar mascarar problemas reais.

Exemplo Prático:

public class ConverterUtils {
    // Sobrescreve o método da classe pai, @Override garante a correção
    @Override
    public String toString() {
        return "Classe de utilitários Converter";
    }
    
    // Marca o método como obsoleto, recomenda usar o método 'formatModern'
    @Deprecated
    public static String convert(String input) {
        return input.toUpperCase();
    }
    
    // Novo método de formatação
    public static String formatModern(String input) {
        // Lógica otimizada
        return "[" + input.trim() + "]";
    }
    
    // Suprime o aviso unchecked (ex: usar ArrayList sem especificar o tipo genérico)
    @SuppressWarnings("unchecked")
    public static List getRawList() {
        return new ArrayList();
    }
}

Tags: Spring Framework Injeção de Dependência desenvolvimento web Spring Boot MyBatis

Publicado em 6-15 16:46 por Thomas