se.jbee.inject.util.Inject Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of silk-di Show documentation
Show all versions of silk-di Show documentation
Silk Java dependency injection framework
/*
* Copyright (c) 2012, Jan Bernitt
*
* Licensed under the Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
*/
package se.jbee.inject.util;
import static se.jbee.inject.Emergence.emergence;
import static se.jbee.inject.Type.raw;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import se.jbee.inject.Array;
import se.jbee.inject.DIRuntimeException.NoSuchResourceException;
import se.jbee.inject.Demand;
import se.jbee.inject.Dependency;
import se.jbee.inject.Expiry;
import se.jbee.inject.Injectable;
import se.jbee.inject.Injector;
import se.jbee.inject.Injectron;
import se.jbee.inject.Precision;
import se.jbee.inject.Repository;
import se.jbee.inject.Resource;
import se.jbee.inject.Source;
import se.jbee.inject.Supplier;
import se.jbee.inject.Type;
/**
* Utility to create/use the core containers {@link Injector} and {@link Injectron}.
*
* @author Jan Bernitt ([email protected])
*/
public final class Inject {
public static Injector from( InjectronSource source ) {
return new SourcedInjector( source );
}
public static Injectable asInjectable( Supplier extends T> supplier, Injector injector ) {
return new SupplierToInjectable( supplier, injector );
}
public static Injectron injectron( Injectable injectable, Resource resource,
Demand demand, Expiry expiry, Repository repository, Source source ) {
return new StaticInjectron( resource, source, demand, expiry, repository, injectable );
}
private static class SupplierToInjectable
implements Injectable {
private final Supplier extends T> supplier;
private final Injector context;
SupplierToInjectable( Supplier extends T> supplier, Injector context ) {
super();
this.supplier = supplier;
this.context = context;
}
@Override
public T instanceFor( Demand demand ) {
return supplier.supply( demand.getDependency(), context );
}
}
private Inject() {
throw new UnsupportedOperationException( "util" );
}
/**
* The default {@link Injector} that gets the initial {@link Injectron}s from a
* {@link InjectronSource}.
*
* @author Jan Bernitt ([email protected])
*/
public static final class SourcedInjector
implements Injector {
private final Map, Injectron>[]> injectrons;
SourcedInjector( InjectronSource source ) {
super();
this.injectrons = initFrom( source );
}
private Map, Injectron>[]> initFrom( InjectronSource source ) {
Injectron>[] injectrons = source.exportTo( this );
Arrays.sort( injectrons, Precision.RESOURCE_COMPARATOR );
Map, Injectron>[]> map = new IdentityHashMap, Injectron>[]>(
injectrons.length );
if ( injectrons.length == 0 ) {
return map;
}
Class> lastRawType = injectrons[0].getResource().getType().getRawType();
int start = 0;
for ( int i = 0; i < injectrons.length; i++ ) {
Class> rawType = injectrons[i].getResource().getType().getRawType();
if ( rawType != lastRawType ) {
map.put( lastRawType, Arrays.copyOfRange( injectrons, start, i ) );
start = i;
}
lastRawType = rawType;
}
map.put( lastRawType, Arrays.copyOfRange( injectrons, start, injectrons.length ) );
return map;
}
@SuppressWarnings ( "unchecked" )
@Override
public T resolve( Dependency dependency ) {
final Type type = dependency.getType();
final boolean array = type.isUnidimensionalArray();
Injectron injectron = applicableInjectron( dependency );
if ( injectron != null ) {
return injectron.instanceFor( dependency );
}
if ( array ) {
return resolveArray( dependency, type.elementType() );
}
if ( type.getRawType() == Injectron.class ) {
Injectron> i = applicableInjectron( dependency.onTypeParameter() );
if ( i != null ) {
return (T) i;
}
}
if ( type.getRawType() == Injector.class ) {
return (T) this;
}
throw noInjectronFor( dependency );
}
private Injectron applicableInjectron( Dependency dependency ) {
return mostPreciseOf( typeInjectrons( dependency.getType() ), dependency );
}
private static Injectron mostPreciseOf( Injectron[] injectrons,
Dependency dependency ) {
if ( injectrons == null ) {
return null;
}
for ( int i = 0; i < injectrons.length; i++ ) {
Injectron injectron = injectrons[i];
if ( injectron.getResource().isApplicableFor( dependency ) ) {
return injectron;
}
}
return null;
}
private NoSuchResourceException noInjectronFor( Dependency dependency ) {
return new NoSuchResourceException( dependency, typeInjectrons( dependency.getType() ) );
}
private T resolveArray( Dependency dependency, Type elementType ) {
if ( elementType.getRawType() == Injectron.class ) {
return resolveInjectronArray( dependency, elementType.parameter( 0 ) );
}
Injectron[] elementInjectrons = typeInjectrons( elementType );
if ( elementInjectrons != null ) {
List elements = new ArrayList( elementInjectrons.length );
addAllApplicable( elements, dependency, elementType, elementInjectrons );
return toArray( elements, elementType );
}
// if there hasn't been binds to that specific wildcard Type
if ( elementType.isLowerBound() ) { // wildcard dependency:
List elements = new ArrayList();
for ( Entry, Injectron>[]> e : injectrons.entrySet() ) {
if ( Type.raw( e.getKey() ).isAssignableTo( elementType ) ) {
//FIXME some of the injectrons are just bridges and such - no real values - recursion causes errors here
@SuppressWarnings ( "unchecked" )
Injectron extends E>[] value = (Injectron extends E>[]) e.getValue();
addAllApplicable( elements, dependency, elementType, value );
}
}
return toArray( elements, elementType );
}
throw noInjectronFor( dependency );
}
private T resolveInjectronArray( Dependency dependency, Type instanceType ) {
Dependency instanceDependency = dependency.typed( instanceType );
if ( instanceType.isLowerBound() ) {
List> res = new ArrayList>();
for ( Entry, Injectron>[]> e : injectrons.entrySet() ) {
if ( raw( e.getKey() ).isAssignableTo( instanceType ) ) {
@SuppressWarnings ( "unchecked" )
Injectron extends I>[] typeInjectrons = (Injectron extends I>[]) e.getValue();
for ( Injectron extends I> i : typeInjectrons ) {
if ( i.getResource().isSuitableFor( instanceDependency ) ) {
res.add( i );
}
}
}
}
return toArray( res, raw( Injectron.class ) );
}
Injectron[] res = typeInjectrons( instanceType );
List> elements = new ArrayList>( res.length );
for ( Injectron i : res ) {
if ( i.getResource().isSuitableFor( instanceDependency ) ) {
elements.add( i );
}
}
return toArray( elements, raw( Injectron.class ) );
}
private static void addAllApplicable( List elements, Dependency dependency,
Type elementType, Injectron extends E>[] elementInjectrons ) {
Dependency elementDependency = dependency.typed( elementType );
for ( int i = 0; i < elementInjectrons.length; i++ ) {
Injectron extends E> injectron = elementInjectrons[i];
if ( injectron.getResource().isApplicableFor( elementDependency ) ) {
elements.add( injectron.instanceFor( elementDependency ) );
}
}
}
@SuppressWarnings ( "unchecked" )
private static T toArray( List extends E> elements, Type elementType ) {
return (T) Array.of( elements, elementType.getRawType() );
}
@SuppressWarnings ( "unchecked" )
private Injectron[] typeInjectrons( Type type ) {
return (Injectron[]) injectrons.get( type.getRawType() );
}
@Override
public String toString() {
StringBuilder b = new StringBuilder();
for ( Entry, Injectron>[]> e : injectrons.entrySet() ) {
b.append( e.getKey() ).append( '\n' );
for ( Injectron> i : e.getValue() ) {
b.append( '\t' ).append( i ).append( '\n' );
}
}
return b.toString();
}
}
private static class StaticInjectron
implements Injectron {
private final Resource resource;
private final Source source;
private final Demand demand;
private final Repository repository;
private final Injectable injectable;
private final Expiry expiry;
StaticInjectron( Resource resource, Source source, Demand demand, Expiry expiry,
Repository repository, Injectable injectable ) {
super();
this.resource = resource;
this.source = source;
this.demand = demand;
this.expiry = expiry;
this.repository = repository;
this.injectable = injectable;
}
@Override
public Resource getResource() {
return resource;
}
@Override
public Source getSource() {
return source;
}
@Override
public Expiry getExpiry() {
return expiry;
}
@Override
public T instanceFor( Dependency super T> dependency ) {
return repository.serve( demand.from( dependency.injectingInto( emergence(
resource.getInstance(), expiry ) ) ), injectable );
}
@Override
public String toString() {
return demand.toString() + resource.getTarget().toString() + " " + source.toString();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy