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
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
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