Install
$ agentstack add skill-snk-devcenter-addon-studio-dependency-injection ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Injeção de Dependência (Guice) — Addon Studio 2.0
Addon Studio 2.0 usa Google Guice como container DI. Anotações estereótipo customizadas fazem auto-scan. Doc descreve regras, padrões, boas práticas DI.
1. Regra de Ouro
Sempre injeção via construtor com @Inject de com.google.inject.Inject.
import com.google.inject.Inject;
@Component
public class MeuService {
private final MeuRepository repository;
private final MeuGateway gateway;
@Inject
public MeuService(MeuRepository repository, MeuGateway gateway) {
this.repository = repository;
this.gateway = gateway;
}
}
> NUNCA @Inject de javax.inject. Sempre com.google.inject.Inject.
2. Estereótipos (Anotações de Auto-Scanning)
Framework scaneia e registra classes com:
| Anotação | Pacote | Gerenciamento | Uso | |:---------|:-------|:--------------|:----| | @Controller | br.com.sankhya.studio.annotations | Automático — NÃO adicionar @Component | Entrypoints REST | | @Repository | br.com.sankhya.studio.stereotypes | Automático — NÃO adicionar @Component | Interfaces de acesso a dados (JapeRepository) | | @Component | br.com.sankhya.studio.stereotypes | Automático | Classes gerais: Services, Adapters, Gateways, Mappers auxiliares | | @ControllerAdvice | br.com.sankhya.studio.web | Automático | Tratamento global de exceções | | @CustomModule | br.com.sankhya.studio.stereotypes | Automático | 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:
@Injectdecom.google.inject.Injectno construtor; depsprivate final.- NÃO adicionar
@Component—@Controllerjá gerenciado pelo framework. - Anatomia completa (
serviceName,transactionType,@Transactional, DTOs): ver skillcontroller.
3.2 @Repository — Interfaces de Acesso a Dados
import br.com.sankhya.sdk.data.repository.JapeRepository;
import br.com.sankhya.studio.stereotypes.Repository;
@Repository
public interface MeuProdutoRepository extends JapeRepository {
// métodos declarativos — o framework gera a implementação
}
Regras:
- Sempre interface (nunca classe concreta).
- Estende
JapeRepository. - NÃO adicionar
@Component— framework gera implementação e registra no Guice. - Injetável direto em qualquer
@Componentou@Controller.
3.3 @Component — Classes Gerais
Pra qualquer classe injetável que não encaixa em @Controller ou @Repository.
Exemplos @Component:
| Tipo | Exemplo | |:-----|:--------| | Servico de aplicacao | ImportarProdutoService | | Servico de negocio | PedidoCreateService | | Servico de infraestrutura | IntegrationConfigurationService | | Gateway/Adapter | DynamicProdutoGateway | | Mapper auxiliar (usado por MapStruct uses={}) | StringMappingNormalizer | | Provider/Resolver | IntegrationPlatformProvider |
import br.com.sankhya.studio.stereotypes.Component;
import com.google.inject.Inject;
@Component
public class ImportarProdutoService {
private final ProdutoRepository repository;
private final DynamicProdutoGateway gateway;
@Inject
public ImportarProdutoService(ProdutoRepository repository,
DynamicProdutoGateway gateway) {
this.repository = repository;
this.gateway = gateway;
}
public List execute() { ... }
}
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.
import br.com.sankhya.studio.stereotypes.CustomModule;
import com.google.inject.AbstractModule;
import com.google.inject.multibindings.Multibinder;
@CustomModule
public class IntegrationPlatformConfig extends AbstractModule {
@Override
protected void configure() {
Multibinder binder =
Multibinder.newSetBinder(binder(), IntegrationPlatformAdapter.class);
binder.addBinding().to(WebReceitaAdapter.class);
// binder.addBinding().to(OutraPlataformaAdapter.class);
}
}
Set injetável:
@Singleton
public class IntegrationPlatformResolver {
private final Map adapters;
@Inject
public IntegrationPlatformResolver(Set adapters) {
this.adapters = adapters.stream()
.collect(Collectors.toMap(IntegrationPlatformAdapter::getTipo, Function.identity()));
}
public IntegrationPlatformAdapter resolve(TipoPlataforma tipo) {
IntegrationPlatformAdapter adapter = adapters.get(tipo);
if (adapter == null) {
throw new IllegalArgumentException("Nenhuma integracao implementada para: " + tipo);
}
return adapter;
}
}
4.2 @Provides — Factory Methods
Pra criar instâncias com configuração especial (ex: clientes HTTP).
> Para wiring completo de cliente Retrofit (deps no build.gradle, interface, interceptor), ver skill retrofit. Os exemplos abaixo cobrem só o lado DI.
import br.com.sankhya.studio.stereotypes.CustomModule;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Singleton;
@CustomModule
public class MeuClientConfig extends AbstractModule {
@Provides
@Singleton
public MeuApiClient provideMeuApiClient(RetrofitClientFactory factory) {
return factory.create(
MeuApiClient.class,
Collections.emptyList(),
"https://api.exemplo.com/"
);
}
@Provides
@Singleton
public MeuApiAuthClient provideMeuAuthClient(RetrofitClientFactory factory,
MeuAuthInterceptor authInterceptor) {
return factory.create(
MeuApiAuthClient.class,
Collections.singletonList(authInterceptor),
"https://api.exemplo.com/"
);
}
}
Regras:
@Providesmarca método como factory.@Singletongarante instância única.- Parâmetros resolvidos automaticamente pelo Guice.
- Classe deve estender
AbstractModulee 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
@Singleton
public class RetrofitCallExecutor {
// 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 |
> @Singleton sem @Component não auto-scaneada. Precisa estar em @CustomModule ou ser injetada por classe que Guice conhece.
6. Provider — Injeção Lazy / Circular
Em dependência circular ou resolução lazy, injete Provider em vez de T.
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@Singleton
public class MeuAuthInterceptor implements Interceptor {
private final Provider authClientProvider;
private final Provider configProvider;
@Inject
public MeuAuthInterceptor(Provider authClientProvider,
Provider configProvider) {
this.authClientProvider = authClientProvider;
this.configProvider = configProvider;
}
@Override
public Response intercept(Chain chain) throws IOException {
// .get() resolve a dependência no momento da chamada (lazy)
MeuAuthClient client = authClientProvider.get();
IntegrationConfigurationService config = configProvider.get();
// ...
}
}
Quando usar Provider
- 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 uses deve 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):
@Controller (entrada)
└── @Inject Service (@Component)
└── @Inject Repository (@Repository — interface)
└── @Inject Gateway concreto (@Component)
└── @Inject Provider / Resolver / Adapter (@Component)
└── resolvido em runtime via @CustomModule + Multibinder
@CustomModule registra bindings explicitos (Multibinder, @Provides @Singleton).
9. Interfaces e implementacoes via Guice
Interfaces abstraem implementacao concreta. Guice resolve a implementacao quando ela e marcada com @Component e implementa a interface.
> Interface so quando ha polimorfismo real — duas ou mais implementacoes, ou troca em runtime (Multibinder, resolucao por parametro). Com uma unica implementacao, injete a classe concreta: @Component sozinho ja e resolvido pelo Guice, e a interface extra nao adiciona nada alem de um arquivo. O limite de um @Component por interface (abaixo) pune justamente a interface criada por habito.
Interface:
public interface ProdutoGateway {
List findAll();
}
Implementação:
@Component
public class DynamicProdutoGateway implements ProdutoGateway {
private final IntegrationPlatformProvider provider;
@Inject
public DynamicProdutoGateway(IntegrationPlatformProvider provider) {
this.provider = provider;
}
@Override
public List findAll() {
return provider.get().produto().findAll();
}
}
> 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:
@Provides
@Singleton
public MeuSegundoInterceptor provideMeuSegundoInterceptor() {
return new MeuSegundoInterceptor();
}
Pontos de injeção que pedem o tipo concreto continuam funcionando sem alteração.
10. Checklist
Nova classe injetável
- [ ] Identificar estereótipo correto (
@Controller,@Repository,@Component). - [ ] Usar
@Injectdecom.google.inject.Injectno construtor. - [ ] Declarar deps
private final, inicializar no construtor. - [ ] NÃO usar
newpra criar deps — sempre injetar. - [ ] NÃO misturar estereótipos (ex:
@Component+@Controller).
Novo módulo customizado
- [ ] Criar classe que estende
AbstractModule. - [ ] Anotar com
@CustomModule. - [ ] Usar
Multibinderpra Strategy Pattern. - [ ] Usar
@Provides @Singletonpra factories. - [ ] Colocar conforme arquitetura do projeto.
Novo interceptor ou singleton
- [ ] Anotar com
@Singleton. - [ ] Dep circular? Usar
Provider. - [ ] Não é
@Component? Garantir registro em algum@CustomModule.
11. Erros Comuns
| Erro | Correção | |:-----|:---------| | Usar javax.inject.Inject | Sempre com.google.inject.Inject. | | Adicionar @Component em @Controller | @Controller já gerenciado. Remove @Component. | | Adicionar @Component em @Repository | @Repository já gerenciado. Remove @Component. | | Criar implementação manual de Repository | Use interface JapeRepository — framework gera implementação. | | Usar new pra instanciar dep | Injete via construtor. Guice resolve automático. | | Dep circular com @Singleton | Use Provider pra quebrar ciclo. | | Classe sem estereótipo que precisa injeção | Adicione @Component ou registre em @CustomModule. | | @Singleton sem @Component e sem módulo | Guice não encontra. Adicione um dos dois. | | Mapper MapStruct com uses sem injectionStrategy | Adicione injectionStrategy = InjectionStrategy.CONSTRUCTOR. | | @Provides em classe sem @CustomModule | 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 denewcontroller— controllers gerenciados automaticamente pelo framework — NÃO anotar @Componentcontroller-advice— advice gerenciado automaticamente pelo framework — NÃO anotar @Componentmapstruct— mappers são registrados no container Guiceretrofit— wiring completo de cliente HTTP (interface + interceptor +@Provides) e exemplos práticos de@Provides @Singletonvalue— injeção de valores de configuração via@Value
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: snk-devcenter
- Source: snk-devcenter/addon-studio
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.