CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-google-dagger--dagger

A fast dependency injector for Java and Android that generates plain Java source code without using reflection or runtime bytecode generation

Pending
Overview
Eval results
Files

assisted-injection.mddocs/

Assisted Injection

Assisted injection in Dagger enables the creation of objects that require both injected dependencies and runtime parameters. This pattern uses factory interfaces to create instances where some parameters are provided by Dagger's dependency injection and others are passed at runtime.

Capabilities

@AssistedInject Annotation

Annotates constructors that require assisted injection, mixing dependencies injected by Dagger with parameters provided at runtime.

/**
 * Annotates constructors for assisted injection (runtime parameter passing)
 */
@Target(ElementType.CONSTRUCTOR)
@Retention(RetentionPolicy.RUNTIME)
@interface AssistedInject {}

Key Features:

  • Cannot be used with scoping annotations (not scoped)
  • Requires a corresponding @AssistedFactory
  • Some parameters are injected by Dagger, others marked with @Assisted
  • Only one constructor per class can have @AssistedInject

Usage Examples:

public class UserSession {
    private final UserService userService;  // Injected by Dagger
    private final User user;                // Passed at runtime
    private final String sessionId;         // Passed at runtime
    
    @AssistedInject
    public UserSession(
        UserService userService,           // Dagger-provided
        @Assisted User user,              // Runtime parameter
        @Assisted String sessionId        // Runtime parameter  
    ) {
        this.userService = userService;
        this.user = user;
        this.sessionId = sessionId;
    }
}

@AssistedFactory Annotation

Annotates factory interfaces or abstract classes that create instances with assisted injection. The factory provides a clean API for creating objects with mixed parameter sources.

/**
 * Annotates factory interfaces/abstract classes for creating assisted injection types
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface AssistedFactory {}

Requirements:

  • Must be abstract class or interface
  • Exactly one abstract method
  • Return type must match the assisted injection type
  • Method parameters must match @Assisted parameters in constructor

Usage Examples:

@AssistedFactory
public interface UserSessionFactory {
    UserSession create(User user, String sessionId);
}

// Usage
public class LoginService {
    private final UserSessionFactory sessionFactory;
    
    @Inject
    public LoginService(UserSessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
    
    public UserSession login(String username, String password) {
        User user = authenticateUser(username, password);
        String sessionId = generateSessionId();
        return sessionFactory.create(user, sessionId);
    }
}

@Assisted Annotation

Annotates constructor parameters that are passed at runtime rather than injected by Dagger. Each @Assisted parameter must have a corresponding parameter in the factory method.

/**
 * Annotates constructor parameters that are passed at runtime (not injected)
 */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@interface Assisted {
    /**
     * Identifier for distinguishing parameters of the same type
     */
    String value() default "";
}

Key Features:

  • Each @Assisted parameter uniquely identified by identifier + type
  • Factory method parameters must match constructor @Assisted parameters
  • Parameters without @Assisted are provided by Dagger
  • Identifier helps distinguish multiple parameters of the same type

Usage Examples:

public class DatabaseConnection {
    private final ConnectionPool pool;     // Injected
    private final String host;            // Runtime parameter
    private final int port;               // Runtime parameter
    private final String database;        // Runtime parameter
    
    @AssistedInject
    public DatabaseConnection(
        ConnectionPool pool,
        @Assisted String host,
        @Assisted int port,
        @Assisted String database
    ) {
        this.pool = pool;
        this.host = host;
        this.port = port;
        this.database = database;
    }
}

@AssistedFactory
public interface DatabaseConnectionFactory {
    DatabaseConnection create(String host, int port, String database);
}

Assisted Parameters with Identifiers

When multiple parameters have the same type, use identifiers to distinguish them:

public class Rectangle {
    private final Graphics graphics;  // Injected
    private final int width;         // Runtime parameter
    private final int height;        // Runtime parameter
    
    @AssistedInject
    public Rectangle(
        Graphics graphics,
        @Assisted("width") int width,
        @Assisted("height") int height
    ) {
        this.graphics = graphics;
        this.width = width;
        this.height = height;
    }
}

@AssistedFactory
public interface RectangleFactory {
    // Parameters must match identifiers and types
    Rectangle create(@Assisted("width") int width, @Assisted("height") int height);
}

Generic Assisted Injection

Assisted injection works with generic types:

public class Repository<T> {
    private final DatabaseService databaseService;  // Injected
    private final Class<T> entityClass;            // Runtime parameter
    private final String tableName;                // Runtime parameter
    
    @AssistedInject
    public Repository(
        DatabaseService databaseService,
        @Assisted Class<T> entityClass,
        @Assisted String tableName
    ) {
        this.databaseService = databaseService;
        this.entityClass = entityClass;
        this.tableName = tableName;
    }
}

@AssistedFactory
public interface RepositoryFactory {
    <T> Repository<T> create(Class<T> entityClass, String tableName);
}

// Usage
public class UserService {
    private final Repository<User> userRepository;
    
    @Inject
    public UserService(RepositoryFactory repositoryFactory) {
        this.userRepository = repositoryFactory.create(User.class, "users");
    }
}

Complex Assisted Injection Patterns

Multiple Factories:

public class ReportGenerator {
    @AssistedInject
    public ReportGenerator(
        ReportService reportService,
        @Assisted ReportType type,
        @Assisted DateRange dateRange,
        @Assisted("format") String format
    ) { /* ... */ }
}

// Different factories for different use cases
@AssistedFactory
public interface DailyReportFactory {
    ReportGenerator create(
        ReportType type, 
        @Assisted("format") String format
    );
}

@AssistedFactory  
public interface CustomReportFactory {
    ReportGenerator create(
        ReportType type,
        DateRange dateRange,
        @Assisted("format") String format
    );
}

Factory with Nullable Parameters:

public class EmailSender {
    @AssistedInject
    public EmailSender(
        EmailService emailService,
        @Assisted String recipient,
        @Assisted @Nullable String cc,
        @Assisted @Nullable String bcc
    ) { /* ... */ }
}

@AssistedFactory
public interface EmailSenderFactory {
    EmailSender create(
        String recipient,
        @Nullable String cc,
        @Nullable String bcc
    );
}

Integration with Components

Assisted factories must be explicitly bound in components:

@Module
public abstract class AssistedInjectModule {
    // No explicit binding needed - Dagger generates the factory implementation
}

@Component(modules = AssistedInjectModule.class)
public interface ApplicationComponent {
    UserSessionFactory userSessionFactory();
    DatabaseConnectionFactory databaseConnectionFactory();
    RepositoryFactory repositoryFactory();
}

Assisted Injection Best Practices

Clear Parameter Naming:

// Good: Clear parameter purposes
@AssistedInject
public FileProcessor(
    Logger logger,                    // Injected
    @Assisted("input") File inputFile,    // Runtime
    @Assisted("output") File outputFile   // Runtime
) { /* ... */ }

// Avoid: Ambiguous parameters
@AssistedInject  
public FileProcessor(
    Logger logger,
    @Assisted File file1,
    @Assisted File file2
) { /* ... */ }

Factory Interface Design:

// Good: Descriptive factory methods
@AssistedFactory
public interface HttpClientFactory {
    HttpClient createWithTimeout(int timeoutSeconds);
    HttpClient createWithAuth(String token, int timeoutSeconds);
}

// Avoid: Generic create method
@AssistedFactory
public interface HttpClientFactory {
    HttpClient create(Object... params);
}

Error Handling:

public class SafeAssistedInjection {
    @AssistedInject
    public SafeAssistedInjection(
        Validator validator,
        @Assisted String input
    ) {
        // Validate runtime parameters
        if (input == null || input.trim().isEmpty()) {
            throw new IllegalArgumentException("Input cannot be null or empty");
        }
        this.validator = validator;
        this.input = validator.validate(input);
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-com-google-dagger--dagger

docs

assisted-injection.md

component-framework.md

index.md

module-system.md

multibindings.md

utility-types.md

tile.json