AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Dependency Injection

skill-snk-devcenter-addon-studio-dependency-injection · by snk-devcenter

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`/`AbstractMo…

No reviews yet
0 installs
6 views
0.0% view→install

Install

$ agentstack add skill-snk-devcenter-addon-studio-dependency-injection

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No 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.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-snk-devcenter-addon-studio-dependency-injection)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
13d ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

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 →
Are you the author of Dependency Injection? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

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:

  • @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;

@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 @Component ou @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:

  • @Provides marca método como factory.
  • @Singleton garante instância única.
  • Parâmetros resolvidos automaticamente pelo Guice.
  • 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
@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

  1. [ ] Identificar estereótipo correto (@Controller, @Repository, @Component).
  2. [ ] Usar @Inject de com.google.inject.Inject no construtor.
  3. [ ] Declarar deps private final, inicializar no construtor.
  4. [ ] NÃO usar new pra criar deps — sempre injetar.
  5. [ ] NÃO misturar estereótipos (ex: @Component + @Controller).

Novo módulo customizado

  1. [ ] Criar classe que estende AbstractModule.
  2. [ ] Anotar com @CustomModule.
  3. [ ] Usar Multibinder pra Strategy Pattern.
  4. [ ] Usar @Provides @Singleton pra factories.
  5. [ ] Colocar conforme arquitetura do projeto.

Novo interceptor ou singleton

  1. [ ] Anotar com @Singleton.
  2. [ ] Dep circular? Usar Provider.
  3. [ ] 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 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

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.