Exemplo Prático

🚧

Feature Experimental. Para acesso prévio envie email para [email protected] informando a appkey do seu projeto

Hello World

Este guia apresenta um exemplo simples para demonstrar a utilização de injeção de dependências, controle transacional, e a definição de entidades e repositórios, seguindo práticas de desenvolvimento modernas.

Configuração

Garanta que seu projeto esteja utilizando a versão 2.0.0 ou superior do SDK, conforme a configuração abaixo no seu arquivo build.gradle.

....
buildscript {
    ...
    dependencies {
        classpath "br.com.sankhya.studio:gradle-plugin:2+"
        classpath "com.google.devtools.ksp:symbol-processing-gradle-plugin:2.0.20-1.0.24"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.0"
    }
}
...

Componentes Principais

1. Entidade

As entidades agora são POJOs (Plain Old Java Objects) anotados, similar ao padrão JPA (Java Persistence API) utilizado em ecossistemas como o Spring. Essa abordagem permite o uso de tipos primitivos e tipos de data modernos, simplificando a manipulação de dados.

📘

Lembre-se que as entidades precisam ser mapeadas no Dicionário de dados da plataforma.

import br.com.sankhya.studio.persistence.Column;
import br.com.sankhya.studio.persistence.Id;
import br.com.sankhya.studio.persistence.JapeEntity;
import lombok.Data;

@Data
@JapeEntity(entity = "Veiculo", table = "TGFVEI")
public class Veiculo {

    @Id
    @Column(name = "CODVEICULO")
    private Long id;

    @Column(name = "PLACA")
    private String placa;

    @Column(name = "ATIVO")
    private Boolean ativo;

}

Tipos Suportados:

  • Long/long
  • Integer/int
  • Boolean/boolean
  • Float/float
  • Double/double
  • BigDecimal
  • BigInteger
  • String
  • Timestamp
  • LocalDate, LocalDateZone, LocalDateTime, LocalDateTimeZone
  • Enums (devem possuir value).

2. Repositório

Para definir um repositório, crie uma interface que estenda JapeRepository. O framework implementará automaticamente os métodos básicos de CRUD (save, findById, delete, etc.) e as consultas que você definir.

É possível declarar consultas customizadas (criterias) com parâmetros nomeados, seja pelo nome do argumento do método ou explicitamente com a anotação @Parameter.


import br.com.sankhya.sdk.data.repository.JapeRepository;  
import br.com.sankhya.studio.stereotypes.Repository;

@Repository  
public interface VeiculoRepository extends JapeRepository<Long, Veiculo> {  
  
    @Criteria(clause="PLACA = :placa")
    public Optional<Veiculo> findByPlaca(String placa);
  
    @Criteria(clause="MODELO = :mod")
    public List<Veiculo> findByModelo(@Parameter("mod") String modeloVeiculo);


}  
  • Retornos Flexíveis: Métodos podem retornar Optional, um POJO ou uma List de objetos.

3. DTO (Data Transfer Object)

DTOs são objetos simples para transferir dados entre camadas (como da requisição para o serviço). Agora, eles suportam Java Bean Validation para validações automáticas e declarativas.

@Data
public class VeiculoDTO {
    @NotBlank(message="Placa é requerido")
    private String placa;
}  

4. Serviço (Lógica de Negócio)

A camada de serviço contém a lógica de negócio da aplicação. Use a anotação @Component e injete as dependências necessárias através do construtor.

A anotação @Transactional garante que as operações no método sejam executadas dentro de uma única transação de banco de dados.


@Component
@RequiredArgsConstructor(onConstructor_ =  @Inject) // Injeção via construtor com Lombok
public class VeiculoService {

    private final VeiculoRepository veiculoRepository;
 
    @Transactional
    public void atualizar(String placa) throws Exception {
        // 1. Busca a entidade no banco. 'veiculoDoBanco'  
        Veiculo veiculoDoBanco = veiculoRepository.findByPlaca(placa)
          .orElseThrow(() -> new RuntimeException("Não encontramos um veículo com este ID."));

        // 2. Modifica a entidade recuperada.
        veiculoDoBanco.setAtivo(true);

        // 3. Persiste a alteração e reatribui a variável.
        Veiculo veiculoAtualizado = veiculoRepository.update(veiculoDoBanco);

        // 4. Se precisarmos excluir em seguida, usamos a instância mais recente (veiculoAtualizado),
        // que já possui o cache, tornando a operação de exclusão mais rápida.
        veiculoRepository.delete(veiculoAtualizado);
    }
}  

5. Controller (Ponto de Entrada)

O Controller expõe a funcionalidade como um serviço acessível externamente. Anote a classe com @Service e defina um serviceName para compor a URL de acesso.

As dependências (como o VeiculoService) são injetadas no construtor.


@Service(serviceName = "VeiculoServiceSP")  
public class VeiculoController {

    private final VeiculoService veiculoService;
    @Inject // Injeção de dependência via construtor
    public VeiculoController(VeiculoService veiculoService) {
        this.veiculoService = veiculoService;
    }
 
    @Transactional
    public void atualizarEExcluirVeiculo(@Valid VeiculoDTO veiculo) throws Exception {
        veiculoService.atualizar(veiculo.getPlaca());
    }

}  
  • URL de Acesso: <endereço_servidor>/<nome_addon>/service.sbr?serviceName=VeiculoServiceSP.atualizarEExcluirVeiculo

Benefícios e Princípios de Desenvolvimento

Adotar esta arquitetura moderniza o desenvolvimento e traz benefícios significativos de organização, manutenibilidade e testabilidade, alinhando o código a princípios consolidados como Clean Code e SOLID.

Injeção de Dependências (ID)

  • O que é? Em vez de uma classe criar suas próprias dependências (ex: new VeiculoRepository()), elas são "injetadas" de fora (pelo construtor, por exemplo).
  • Legibilidade e Clean Code: O construtor de uma classe declara explicitamente tudo o que ela precisa para funcionar. Isso torna as dependências claras e o código mais fácil de entender.
  • Princípio da Inversão de Dependência (SOLID): A VeiculoService não depende da implementação concreta do VeiculoRepository, mas sim de sua interface (abstração). Isso desacopla o código, permitindo que a implementação do repositório seja trocada sem impactar a lógica de negócio.
  • Testabilidade: Facilita a criação de testes unitários. É possível "mockar" (simular) o VeiculoRepository para testar a VeiculoService de forma isolada, sem a necessidade de uma conexão real com o banco de dados.

Definição de Repositórios

  • O que é? O Padrão de Repositório abstrai a camada de acesso a dados, tratando a fonte de dados como uma coleção de objetos.
  • Legibilidade e Clean Code: Centraliza toda a lógica de acesso a dados em um único lugar (a interface do repositório). A camada de serviço (VeiculoService) apenas utiliza métodos como findByPlaca, sem precisar se preocupar com a construção de queries SQL ou com a forma como os dados são persistidos.
  • Princípio da Responsabilidade Única (SOLID): O repositório tem uma única responsabilidade: gerenciar a persistência da entidade Veiculo. A classe de serviço tem outra: orquestrar a lógica de negócio. Essa separação de preocupações é a base de uma arquitetura limpa e organizada, tornando o código mais fácil de manter e escalar.