Configura, revisa e debuga DI Guice em Sankhya Addon Studio — `@Inject` de `com.google.inject`, `@Component`, `@CustomModule`, `Provider<T>`, `Multibinder`, `@Singleton`, escopos. Use ao montar wiring, criar/alterar módulos Guice, revisar/auditar dependências, diagnosticar `ConfigurationException`/`CreationException`/binding ausente, ou ao tocar em código com `@Inject`/`@CustomModule`/`AbstractModule`.
Installation
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Configura, revisa e debuga DI Guice em Sankhya Addon Studio — `@Inject` de `com.google.inject`, `@Component`, `@CustomModule`, `Provider<T>`, `Multibinder`, `@Singleton`, escopos. Use ao montar wiring, criar/alterar módulos Guice, revisar/auditar dependências, diagnosticar `ConfigurationException`/`CreationException`/binding ausente, ou ao tocar em código com `@Inject`/`@CustomModule`/`AbstractModule`.
Módulos Guice customizados (equivale a AbstractModule)
Quando usar cada estereótipo
@Controller -> Entrypoints REST (serviceName obrigatório com sufixo "SP")
@Repository -> Interfaces JapeRepository (NÃO crie implementação manual)
@Component -> Todo o resto que precisa ser injetado
@CustomModule -> Módulos de configuração Guice (bindings manuais)
@ControllerAdvice -> Handler global de exceções
3. Classes por Estereótipo
3.1 @Controller — Entrypoints REST
Regras DI relevantes:
@Inject de com.google.inject.Inject no construtor; deps private final.
NÃO adicionar @Component — @Controller já gerenciado pelo framework.
Anatomia completa (serviceName, transactionType, @Transactional, DTOs): ver skill controller.
3.2 @Repository — Interfaces de Acesso a Dados
import br.com.sankhya.sdk.data.repository.JapeRepository;
import br.com.sankhya.studio.stereotypes.Repository;
@RepositorypublicinterfaceMeuProdutoRepositoryextendsJapeRepository<Integer, MeuProduto> {
// métodos declarativos — o framework gera a implementação
}
Regras:
Sempre interface (nunca classe concreta).
Estende JapeRepository<PKType, EntityType>.
NÃO adicionar @Component — framework gera implementação e registra no Guice.
Injetável direto em qualquer @Component ou @Controller.
3.3 @Component — Classes Gerais
Pra qualquer classe injetável que não encaixa em @Controller ou @Repository.
3.4 @ControllerAdvice — Tratamento Global de Exceções
Tratamento centralizado de exceções vindas dos @Controller. Auto-gerenciado — não adicionar @Component.
Ver controller-advice para anatomia completa, regras críticas (handler nunca retorna void, múltiplas exceções por handler, rollback automático, proibição de Exception.class) e níveis de log.
4. Módulos Customizados (@CustomModule)
Quando auto-scan insuficiente (bindings manuais, Multibinder, @Provides), crie módulo Guice com @CustomModule.
4.1 Multibinder — Strategy Pattern
Registra múltiplas implementações de interface pra resolução dinâmica runtime.
Classe deve estender AbstractModule e ter @CustomModule.
5. Escopo: @Singleton
Guice padrão cria nova instância a cada injeção. Use @Singleton pra instância única.
import com.google.inject.Singleton;
@Component@SingletonpublicclassRetrofitCallExecutor {
// Uma única instância reutilizada em toda a aplicação
}
Quando usar @Singleton
Usar @Singleton
Não usar (padrão)
Clientes HTTP, executors, factories
Services de domínio
Resolvers e registries
Gateways e Adapters
Interceptors (OkHttp, Auth)
Controllers
Caches e pools
Mappers auxiliares
@Singletonsem@Component não auto-scaneada. Precisa estar em @CustomModule ou ser injetada por classe que Guice conhece.
6. Provider<T> — Injeção Lazy / Circular
Em dependência circular ou resolução lazy, injete Provider<T> em vez de T.
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@SingletonpublicclassMeuAuthInterceptorimplementsInterceptor {
privatefinal Provider<MeuAuthClient> authClientProvider;
privatefinal Provider<IntegrationConfigurationService> configProvider;
@InjectpublicMeuAuthInterceptor(Provider<MeuAuthClient> authClientProvider,
Provider<IntegrationConfigurationService> configProvider) {
this.authClientProvider = authClientProvider;
this.configProvider = configProvider;
}
@Overridepublic Response intercept(Chain chain)throws IOException {
// .get() resolve a dependência no momento da chamada (lazy)MeuAuthClientclient= authClientProvider.get();
IntegrationConfigurationServiceconfig= configProvider.get();
// ...
}
}
Quando usar Provider<T>
Dependência circular: A depende de B que depende de A.
Singleton com dep request-scoped: ex: interceptor singleton que precisa service com contexto.
Lazy init: adiar criação de objeto custoso até primeiro uso.
7. MapStruct e o Container Guice
Mappers MapStruct registrados automaticamente no Guice (config global defaultComponentModel = "jakarta") — injetáveis direto via @Inject no construtor. Classe em usesdeve ser @Component; com uses (ou abstract class com @Inject), declare injectionStrategy = InjectionStrategy.CONSTRUCTOR pra garantir que o Guice injete via construtor. Detalhes e tipos de mapper: ver skill mapstruct.
8. Padrão tipico de wiring DI
Fluxo comum (ilustrativo — skill nao opina sobre arquitetura, ajuste a sua):
Guice resolve ProdutoGateway -> DynamicProdutoGateway automático porque DynamicProdutoGateway é @Component e implementa interface.
Exceção — JIT binding do Guice: classe concreta com construtor público sem argumentos (ou construtor @Inject) é resolvida just-in-time pelo Guice mesmo sem stereotype (ex.: RetrofitClientFactory da skill retrofit). Interface sempre exige implementação @Component ou binding em @CustomModule.
Limite: UM @Component por interface (Guice/BindingAlreadySet)
O DependencyInjector gerado binda cada@Component a todas as interfaces que ele implementa (bind(Interface.class).to(Impl.class)). Consequência: no máximo um@Component por interface no addon inteiro (o limite cruza pacotes — cada pacote gera seu DependencyInjector, mas todos entram no mesmo injector no deploy).
Dois @Component implementando a mesma interface derrubam o deploy — mesmo que nenhum ponto de injeção peça a interface (todos pedindo o tipo concreto não salva):
[Guice/BindingAlreadySet]: okhttp3.Interceptor was bound multiple times.
Feedback tardio: build e testes passam. O erro só aparece na criação do injector no Wildfly, durante o deploy.
Fix: a classe "excedente" perde o stereotype (@Component/@Singleton) e é provida via @Provides @Singleton num @CustomModule — @Provides binda apenas o tipo concreto, sem tocar na interface:
Guice não encontra provider. Adicione @CustomModule.
Guice/BindingAlreadySet no deploy (build/testes passam)
Dois @Component implementam a mesma interface. Remova o stereotype de um deles e proveja via @Provides @Singleton do tipo concreto em @CustomModule (ver seção 9).
Skills relacionadas
addon-studio — regras universais sobre @Inject (com.google.inject) e proibição de new
controller — controllers gerenciados automaticamente pelo framework — NÃO anotar @Component
controller-advice — advice gerenciado automaticamente pelo framework — NÃO anotar @Component
mapstruct — mappers são registrados no container Guice
retrofit — wiring completo de cliente HTTP (interface + interceptor + @Provides) e exemplos práticos de @Provides @Singleton
value — injeção de valores de configuração via @Value