package org.qi4j.runtime.injection.provider;
import org.qi4j.api.composite.NoSuchCompositeException;
import org.qi4j.api.object.NoSuchObjectException;
import org.qi4j.bootstrap.InvalidInjectionException;
import org.qi4j.runtime.composite.UsesInstance;
import org.qi4j.runtime.injection.DependencyModel;
import org.qi4j.runtime.injection.InjectionContext;
import org.qi4j.runtime.injection.InjectionProvider;
import org.qi4j.runtime.injection.InjectionProviderFactory;
import org.qi4j.runtime.model.Resolution;
import org.qi4j.runtime.structure.ModuleInstance;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* JAVADOC
*/
public final class UsesInjectionProviderFactory
implements InjectionProviderFactory
{
public UsesInjectionProviderFactory()
{
}
public InjectionProvider newInjectionProvider( Resolution resolution, DependencyModel dependencyModel )
throws InvalidInjectionException
{
return new UsesInjectionProvider( dependencyModel );
}
private class UsesInjectionProvider
implements InjectionProvider
{
private final DependencyModel dependency;
public UsesInjectionProvider( DependencyModel dependency )
{
this.dependency = dependency;
}
@SuppressWarnings( "unchecked" )
public Object provideInjection( InjectionContext context )
throws InjectionProviderException
{
UsesInstance uses = context.uses();
Class injectionType = dependency.rawInjectionType();
Object usesObject = uses.useForType( injectionType );
if( usesObject == null && !dependency.optional())
{
// No @Uses object provided
// Try instantiating a Transient or Object for the given type
ModuleInstance moduleInstance = context.module();
try
{
if (context.instance() != null)
uses = uses.use( context.instance() );
usesObject = moduleInstance.newTransient( injectionType, uses.toArray() );
} catch( NoSuchCompositeException e )
{
try
{
usesObject = moduleInstance.newObject( injectionType, uses.toArray() );
} catch( NoSuchObjectException e1 )
{
// Could not instantiate an instance - to try instantiate as plain class
try
{
usesObject = injectionType.newInstance();
} catch( Throwable e2 )
{
// Could not instantiate - try with this as first argument
try
{
Constructor constructor = injectionType.getDeclaredConstructor( context.instance().getClass() );
if (!constructor.isAccessible())
constructor.setAccessible( true );
usesObject = constructor.newInstance( context.instance() );
} catch( Throwable e3 )
{
// Really can't instantiate it - ignore
}
}
}
}
if( usesObject != null )
{
context.setUses( context.uses().use( usesObject ) ); // Use this for other injections in same graph
}
return usesObject;
}
else
{
return usesObject;
}
}
}
}