KOIN - Kotlin simple Dependency Injection Framework for JavaScript/Browser platform
—
Comprehensive error handling with specific exception types for different failure scenarios in dependency injection and container management.
Handle errors related to dependency definition and resolution failures.
/**
* Exception thrown when definition is not found during resolution
*/
class NoDefinitionFoundException extends Error {
/**
* Create exception for missing definition
* @param message - Error description
*/
constructor(message: string);
/**
* The qualifier that was not found (if any)
*/
qualifier?: Qualifier;
/**
* The type that was being resolved
*/
type?: any;
}
/**
* Exception thrown when definition override is not allowed
*/
class DefinitionOverrideException extends Error {
/**
* Create exception for definition override conflict
* @param message - Error description
*/
constructor(message: string);
/**
* The definition that conflicts
*/
definition?: BeanDefinition<any>;
}
/**
* Exception thrown when instance creation fails
*/
class InstanceCreationException extends Error {
/**
* Create exception for instance creation failure
* @param message - Error description
* @param cause - Underlying cause of failure
*/
constructor(message: string, cause?: Error);
/**
* The underlying cause of the creation failure
*/
cause?: Error;
/**
* The definition that failed to create instance
*/
definition?: BeanDefinition<any>;
}Usage Examples:
import {
GlobalContext,
NoDefinitionFoundException,
DefinitionOverrideException,
InstanceCreationException,
named
} from "koin-core";
class ServiceManager {
async getService(serviceName) {
try {
const koin = GlobalContext.get();
return koin.get(named(serviceName));
} catch (error) {
if (error instanceof NoDefinitionFoundException) {
console.error(`Service '${serviceName}' not found in DI container`);
console.error(`Qualifier: ${error.qualifier?.value}`);
console.error(`Type: ${error.type?.name}`);
// Provide fallback or default service
return this.createFallbackService(serviceName);
} else if (error instanceof InstanceCreationException) {
console.error(`Failed to create service '${serviceName}'`);
console.error(`Cause: ${error.cause?.message}`);
// Log additional context and re-throw
this.logCreationFailure(error);
throw new Error(`Service creation failed: ${error.message}`);
} else {
// Re-throw unknown errors
throw error;
}
}
}
registerService(serviceName, factory, allowOverride = false) {
try {
const koin = GlobalContext.get();
const module = module((builder) => {
builder.single(named(serviceName), factory);
});
if (allowOverride) {
// Handle override explicitly
koin.declare(factory(), named(serviceName), [], true);
} else {
loadKoinModules([module]);
}
} catch (error) {
if (error instanceof DefinitionOverrideException) {
console.error(`Service '${serviceName}' already exists`);
console.error(`Existing definition: ${error.definition?.qualifier?.value}`);
if (allowOverride) {
// Force override
this.forceOverrideService(serviceName, factory);
} else {
throw new Error(`Service '${serviceName}' already registered`);
}
}
}
}
}Handle errors related to scope lifecycle and management.
/**
* Exception thrown when attempting to use a closed scope
*/
class ClosedScopeException extends Error {
/**
* Create exception for closed scope access
* @param scopeId - The ID of the closed scope
*/
constructor(scopeId: string);
/**
* ID of the scope that was closed
*/
scopeId: string;
}
/**
* Exception thrown when scope doesn't exist
*/
class ScopeNotCreatedException extends Error {
/**
* Create exception for non-existent scope
* @param scopeId - The ID of the missing scope
*/
constructor(scopeId: string);
/**
* ID of the scope that doesn't exist
*/
scopeId: string;
}
/**
* Exception thrown when scope already exists
*/
class ScopeAlreadyCreatedException extends Error {
/**
* Create exception for duplicate scope creation
* @param scopeId - The ID of the existing scope
*/
constructor(scopeId: string);
/**
* ID of the scope that already exists
*/
scopeId: string;
}
/**
* Exception thrown when scope definition is not found
*/
class NoScopeDefFoundException extends Error {
/**
* Create exception for missing scope definition
* @param message - Error description
*/
constructor(message: string);
/**
* The scope qualifier that was not found
*/
scopeQualifier?: Qualifier;
}
/**
* Exception thrown when scope value is missing
*/
class MissingScopeValueException extends Error {
/**
* Create exception for missing scope value
* @param message - Error description
*/
constructor(message: string);
}Usage Examples:
import {
GlobalContext,
ClosedScopeException,
ScopeNotCreatedException,
ScopeAlreadyCreatedException,
NoScopeDefFoundException,
named
} from "koin-core";
class ScopeManager {
constructor() {
this.activeScopes = new Map();
}
async createUserSession(userId) {
const scopeId = `session-${userId}`;
try {
const koin = GlobalContext.get();
const scope = koin.createScope(scopeId, named("session"));
this.activeScopes.set(userId, scope);
return scope;
} catch (error) {
if (error instanceof ScopeAlreadyCreatedException) {
console.warn(`Session scope for user ${userId} already exists`);
// Return existing scope
return koin.getScope(scopeId);
} else if (error instanceof NoScopeDefFoundException) {
console.error(`Session scope definition not found`);
console.error(`Missing scope qualifier: ${error.scopeQualifier?.value}`);
throw new Error("Session management not configured");
} else {
throw error;
}
}
}
async getUserSession(userId) {
const scopeId = `session-${userId}`;
try {
const koin = GlobalContext.get();
const scope = koin.getScope(scopeId);
// Try to get user session from scope
return scope.get(named("userSession"));
} catch (error) {
if (error instanceof ScopeNotCreatedException) {
console.error(`No session scope found for user ${userId}`);
// Create new session automatically
const newScope = await this.createUserSession(userId);
return newScope.get(named("userSession"));
} else if (error instanceof ClosedScopeException) {
console.error(`Session scope for user ${userId} is closed`);
// Remove from active scopes and recreate
this.activeScopes.delete(userId);
const newScope = await this.createUserSession(userId);
return newScope.get(named("userSession"));
} else {
throw error;
}
}
}
async closeUserSession(userId) {
const scope = this.activeScopes.get(userId);
if (scope) {
try {
scope.close();
this.activeScopes.delete(userId);
console.log(`Session closed for user ${userId}`);
} catch (error) {
if (error instanceof ClosedScopeException) {
// Already closed, just clean up
this.activeScopes.delete(userId);
} else {
throw error;
}
}
}
}
}Handle errors related to parameter injection and property access.
/**
* Exception thrown when required parameter is not found
*/
class NoParameterFoundException extends Error {
/**
* Create exception for missing parameter
* @param message - Error description
*/
constructor(message: string);
/**
* Parameter index that was requested
*/
parameterIndex?: number;
/**
* Parameter type that was requested
*/
parameterType?: any;
}
/**
* Exception thrown when parameter definition has errors
*/
class DefinitionParameterException extends Error {
/**
* Create exception for parameter definition error
* @param message - Error description
*/
constructor(message: string);
/**
* The definition that has parameter issues
*/
definition?: BeanDefinition<any>;
}
/**
* Exception thrown when property is not found
*/
class MissingPropertyException extends Error {
/**
* Create exception for missing property
* @param key - The property key that was not found
*/
constructor(key: string);
/**
* The property key that was missing
*/
key: string;
}
/**
* Exception thrown when property file is not found
*/
class NoPropertyFileFoundException extends Error {
/**
* Create exception for missing property file
* @param message - Error description
*/
constructor(message: string);
/**
* The property file path that was not found
*/
filePath?: string;
}Usage Examples:
import {
module,
parametersOf,
NoParameterFoundException,
DefinitionParameterException,
MissingPropertyException,
KoinComponent
} from "koin-core";
const dynamicModule = module((builder) => {
builder.factory((scope, params) => {
try {
// Validate required parameters
if (params.isEmpty()) {
throw new DefinitionParameterException("Database connection requires parameters");
}
const host = params.elementAt(0);
const port = params.elementAt(1);
if (!host || !port) {
throw new DefinitionParameterException("Host and port parameters required");
}
return new DatabaseConnection(host, port);
} catch (error) {
if (error instanceof NoParameterFoundException) {
console.error(`Parameter missing: index ${error.parameterIndex}, type ${error.parameterType?.name}`);
// Use default parameters
return new DatabaseConnection("localhost", 5432);
}
throw error;
}
});
});
class ConfigurableService extends KoinComponent {
constructor() {
super();
this.loadConfiguration();
}
loadConfiguration() {
try {
// Try to load configuration properties
this.apiUrl = this.getProperty("api.url");
this.timeout = this.getProperty("api.timeout", 5000);
this.retries = this.getProperty("api.retries", 3);
} catch (error) {
if (error instanceof MissingPropertyException) {
console.error(`Missing required property: ${error.key}`);
// Provide sensible defaults
switch (error.key) {
case "api.url":
this.apiUrl = "https://api.default.com";
break;
case "api.timeout":
this.timeout = 5000;
break;
case "api.retries":
this.retries = 3;
break;
default:
throw new Error(`Required configuration missing: ${error.key}`);
}
} else {
throw error;
}
}
}
async createConnection(host, port) {
try {
const connection = this.get(named("database"), () =>
parametersOf(host, port)
);
return connection;
} catch (error) {
if (error instanceof DefinitionParameterException) {
console.error(`Parameter error: ${error.message}`);
console.error(`Definition: ${error.definition?.qualifier?.value}`);
// Try with default parameters
const defaultConnection = this.get(named("database"), () =>
parametersOf("localhost", 5432)
);
return defaultConnection;
}
throw error;
}
}
}Handle errors related to application lifecycle and state management.
/**
* Exception thrown when Koin application is already started
*/
class KoinApplicationAlreadyStartedException extends Error {
/**
* Create exception for duplicate application start
* @param message - Error description
*/
constructor(message: string);
}
/**
* Exception thrown when trying to access Koin before it's started
*/
class IllegalStateException extends Error {
/**
* Create exception for illegal state access
* @param message - Error description
*/
constructor(message: string);
}Usage Examples:
import {
startKoin,
stopKoin,
GlobalContext,
KoinApplicationAlreadyStartedException,
IllegalStateException
} from "koin-core";
class ApplicationLifecycle {
constructor() {
this.isInitialized = false;
}
async start() {
try {
if (this.isInitialized) {
console.log("Application already initialized");
return;
}
startKoin((app) => {
app.modules([coreModule, apiModule]);
app.printLogger();
});
this.isInitialized = true;
console.log("Application started successfully");
} catch (error) {
if (error instanceof KoinApplicationAlreadyStartedException) {
console.warn("Koin application already started, skipping initialization");
this.isInitialized = true;
} else {
console.error("Failed to start application:", error.message);
throw error;
}
}
}
async stop() {
try {
if (!this.isInitialized) {
console.log("Application not initialized, nothing to stop");
return;
}
stopKoin();
this.isInitialized = false;
console.log("Application stopped successfully");
} catch (error) {
console.error("Error stopping application:", error.message);
// Force cleanup
this.isInitialized = false;
throw error;
}
}
getService(serviceName) {
try {
if (!this.isInitialized) {
throw new IllegalStateException("Application not initialized");
}
const koin = GlobalContext.get();
if (!koin) {
throw new IllegalStateException("Koin container not available");
}
return koin.get(named(serviceName));
} catch (error) {
if (error instanceof IllegalStateException) {
console.error(`Illegal state: ${error.message}`);
throw new Error("Service not available - application not ready");
}
throw error;
}
}
}Implement recovery strategies for robust error handling.
/**
* Error recovery utility for dependency injection failures
*/
class DependencyRecovery {
static createFallbackStrategy(primaryFactory, fallbackFactory) {
return (scope, params) => {
try {
return primaryFactory(scope, params);
} catch (error) {
console.warn("Primary factory failed, using fallback:", error.message);
return fallbackFactory(scope, params);
}
};
}
static createRetryStrategy(factory, maxRetries = 3, delay = 1000) {
return async (scope, params) => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await factory(scope, params);
} catch (error) {
if (attempt === maxRetries) {
throw error;
}
console.warn(`Attempt ${attempt} failed, retrying in ${delay}ms:`, error.message);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
};
}
}Usage Examples:
import { module, DependencyRecovery } from "koin-core";
const resilientModule = module((builder) => {
// Service with fallback strategy
builder.single(
DependencyRecovery.createFallbackStrategy(
(scope, params) => new PrimaryDatabaseService(),
(scope, params) => new FallbackDatabaseService()
)
);
// Service with retry strategy
builder.factory(
DependencyRecovery.createRetryStrategy(
async (scope, params) => new ExternalApiClient(),
3, // max retries
2000 // delay between retries
)
);
});/** Base error types for Koin dependency injection */
/** Definition and resolution errors */
class NoDefinitionFoundException extends Error {
qualifier?: Qualifier;
type?: any;
}
class DefinitionOverrideException extends Error {
definition?: BeanDefinition<any>;
}
class InstanceCreationException extends Error {
cause?: Error;
definition?: BeanDefinition<any>;
}
/** Scope-related errors */
class ClosedScopeException extends Error {
scopeId: string;
}
class ScopeNotCreatedException extends Error {
scopeId: string;
}
class ScopeAlreadyCreatedException extends Error {
scopeId: string;
}
class NoScopeDefFoundException extends Error {
scopeQualifier?: Qualifier;
}
class MissingScopeValueException extends Error {}
/** Parameter and property errors */
class NoParameterFoundException extends Error {
parameterIndex?: number;
parameterType?: any;
}
class DefinitionParameterException extends Error {
definition?: BeanDefinition<any>;
}
class MissingPropertyException extends Error {
key: string;
}
class NoPropertyFileFoundException extends Error {
filePath?: string;
}
/** Application state errors */
class KoinApplicationAlreadyStartedException extends Error {}
class IllegalStateException extends Error {}Install with Tessl CLI
npx tessl i tessl/maven-io-insert-koin--koin-core-js