Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support using @Priority on Providers #43

Merged
merged 1 commit into from
Jan 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

Expand All @@ -29,6 +31,7 @@ static interface Bean
{
}

// base priority of default implementation is 0
static class DefaultBean
implements Bean
{
Expand All @@ -46,21 +49,78 @@ static class HighPriorityBean
{
}

static class LowPriorityBean
// base priority of non-default (alternative) implementation is Integer.MIN_VALUE
static class AlternativeBean
implements Bean
{
}

@javax.annotation.Priority( -5000 )
static class LowPriorityProvider
implements javax.inject.Provider<Bean>
{
@Override
public Bean get()
{
return new DefaultBean();
}
}

@javax.annotation.Priority( 5000 )
static class HighPriorityProvider
implements javax.inject.Provider<Bean>
{
@Override
public Bean get()
{
return new DefaultBean();
}
}

@javax.annotation.Priority( -5000 )
static class LowPriorityGuiceProvider
implements Provider<Bean>
{
@Override
public Bean get()
{
return new DefaultBean();
}
}

@javax.annotation.Priority( 5000 )
static class HighPriorityGuiceProvider
implements Provider<Bean>
{
@Override
public Bean get()
{
return new DefaultBean();
}
}

static Injector injector = Guice.createInjector( new AbstractModule()
{
@Override
protected void configure()
{
bind( Bean.class ).annotatedWith( Names.named( "LO" ) ).to( LowPriorityBean.class );
bind( Bean.class ).annotatedWith( Names.named( "ALT" ) ).to( AlternativeBean.class );
bind( Bean.class ).annotatedWith( Names.named( "HI" ) ).to( HighPriorityBean.class );
bind( Bean.class ).to( DefaultBean.class );
bind( Bean.class ).annotatedWith( Names.named( "MED" ) ).to( MediumPriorityBean.class );
binder().withSource( Sources.prioritize( 2000 ) ).bind( Bean.class ).annotatedWith( Names.named( "SRC" ) ).to( DefaultBean.class );
LinkedBindingBuilder<Bean> hi = bind( Bean.class ).annotatedWith( Names.named( "(HI)" ) );
LinkedBindingBuilder<Bean> lo = bind( Bean.class ).annotatedWith( Names.named( "(LO)" ) );
try
{
hi.toProvider( new HighPriorityProvider() );
lo.toProvider( LowPriorityProvider.class );
}
catch ( NoSuchMethodError e ) // Guice3 doesn't let you bind javax.inject.Providers
{
hi.toProvider( new HighPriorityGuiceProvider() );
lo.toProvider( new LowPriorityGuiceProvider() );
}
}
} );

Expand All @@ -73,11 +133,13 @@ public void testPriorityOverride()
i = locator.<Named, Bean> locate( Key.get( Bean.class, Named.class ) ).iterator();

assertTrue( i.hasNext() );
assertEquals( Names.named( "(HI)" ), i.next().getKey() );
assertEquals( Names.named( "HI" ), i.next().getKey() );
assertEquals( Names.named( "SRC" ), i.next().getKey() );
assertEquals( Names.named( "MED" ), i.next().getKey() );
assertEquals( Names.named( "default" ), i.next().getKey() );
assertEquals( Names.named( "LO" ), i.next().getKey() );
assertEquals( Names.named( "(LO)" ), i.next().getKey() );
assertEquals( Names.named( "ALT" ), i.next().getKey() );
assertFalse( i.hasNext() );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.google.inject.spi.InstanceBinding;
import com.google.inject.spi.LinkedKeyBinding;
import com.google.inject.spi.ProviderInstanceBinding;
import com.google.inject.spi.ProviderKeyBinding;
import com.google.inject.spi.UntargettedBinding;

/**
Expand Down Expand Up @@ -104,23 +105,24 @@ public static <T extends Annotation> T getAnnotation( final Binding<?> binding,
{
final boolean isPriority = Priority.class.equals( annotationType );

// peek behind servlet/filter extension bindings when checking priority, so we can order them by rank
final Class<?> implementation =
binding.acceptTargetVisitor( HAS_GUICE_SERVLET && isPriority ? ServletFinder.THIS : ClassFinder.THIS );
final Class<?> annotationSource =
// when looking for @Priority also consider annotations on providers (and servlets/filters if available)
binding.acceptTargetVisitor( isPriority ? ( HAS_GUICE_SERVLET ? ServletFinder.THIS : ProviderFinder.THIS )
: ClassFinder.THIS );

T annotation = null;
if ( null != implementation )
if ( null != annotationSource )
{
annotation = implementation.getAnnotation( annotationType );
annotation = annotationSource.getAnnotation( annotationType );
if ( null == annotation )
{
if ( HAS_JSR250_PRIORITY && isPriority )
{
annotation = adaptJsr250( binding, implementation );
annotation = adaptJsr250( binding, annotationSource );
}
else if ( Description.class.equals( annotationType ) )
{
annotation = adaptLegacy( binding, implementation );
annotation = adaptLegacy( binding, annotationSource );
}
}
}
Expand Down Expand Up @@ -193,7 +195,17 @@ public Class<?> visit( final InstanceBinding<?> binding )
@Override
public Class<?> visit( final ProviderInstanceBinding<?> binding )
{
final Provider<?> provider = Guice4.getProviderInstance( binding );
return peekBehind( Guice4.getProviderInstance( binding ) );
}

@Override
public Class<?> visit( final ExposedBinding<?> binding )
{
return binding.getPrivateElements().getInjector().getBinding( binding.getKey() ).acceptTargetVisitor( this );
}

final Class<?> peekBehind( final Provider<?> provider )
{
if ( provider instanceof DeferredProvider<?> )
{
try
Expand All @@ -208,19 +220,45 @@ public Class<?> visit( final ProviderInstanceBinding<?> binding )
}
return null;
}
}

/**
* {@link ClassFinder} that also returns {@link Provider} implementations.
*/
static class ProviderFinder
extends ClassFinder
{
// ----------------------------------------------------------------------
// Constants
// ----------------------------------------------------------------------

@SuppressWarnings( "hiding" )
static final BindingTargetVisitor<Object, Class<?>> THIS = new ProviderFinder();

// ----------------------------------------------------------------------
// Public methods
// ----------------------------------------------------------------------

@Override
public Class<?> visit( final ProviderInstanceBinding<?> binding )
{
final Provider<?> provider = Guice4.getProviderInstance( binding );
final Class<?> providedClass = peekBehind( provider );
return null != providedClass ? providedClass : provider.getClass();
}

@Override
public Class<?> visit( final ExposedBinding<?> binding )
public Class<?> visit( final ProviderKeyBinding<?> binding )
{
return binding.getPrivateElements().getInjector().getBinding( binding.getKey() ).acceptTargetVisitor( this );
return binding.getProviderKey().getTypeLiteral().getRawType();
}
}

/**
* {@link ClassFinder} that can also peek behind servlet/filter bindings.
* {@link ProviderFinder} that also returns servlet/filter implementations.
*/
static final class ServletFinder
extends ClassFinder
extends ProviderFinder
implements com.google.inject.servlet.ServletModuleTargetVisitor<Object, Class<?>>
{
// ----------------------------------------------------------------------
Expand Down