blob: 6fb63bdbf6d7cb23f6bfdf314c070ba4425ed08d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2013 Sonatype, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Stuart McCulloch (Sonatype, Inc.) - initial API and implementation
*******************************************************************************/
package org.eclipse.sisu.inject;
import java.lang.annotation.Annotation;
import javax.inject.Provider;
import org.eclipse.sisu.BeanEntry;
import org.eclipse.sisu.Description;
import com.google.inject.Binding;
import com.google.inject.Scopes;
/**
* Lazy {@link BeanEntry} backed by a qualified {@link Binding} and an assigned rank.
*/
final class LazyBeanEntry<Q extends Annotation, T>
implements BeanEntry<Q, T>
{
// ----------------------------------------------------------------------
// Implementation fields
// ----------------------------------------------------------------------
private final Q qualifier;
final Binding<T> binding;
private final Provider<T> provider;
private final int rank;
// ----------------------------------------------------------------------
// Constructors
// ----------------------------------------------------------------------
@SuppressWarnings( "unchecked" )
LazyBeanEntry( final Q qualifier, final Binding<T> binding, final int rank )
{
if ( null != qualifier && com.google.inject.name.Named.class == qualifier.annotationType() )
{
this.qualifier = (Q) new JsrNamed( (com.google.inject.name.Named) qualifier );
}
else
{
this.qualifier = qualifier;
}
this.binding = binding;
this.rank = rank;
if ( Scopes.isSingleton( binding ) )
{
this.provider = binding.getProvider();
}
else
{
// use Guice's singleton logic to get lazy-loading without introducing extra locks
this.provider = Scopes.SINGLETON.scope( binding.getKey(), binding.getProvider() );
}
}
// ----------------------------------------------------------------------
// Public methods
// ----------------------------------------------------------------------
public Q getKey()
{
return qualifier;
}
public T getValue()
{
return provider.get();
}
public T setValue( final T value )
{
throw new UnsupportedOperationException();
}
public Provider<T> getProvider()
{
return binding.getProvider();
}
@SuppressWarnings( "deprecation" )
public String getDescription()
{
final Object source = getSource();
if ( source instanceof DescribedBinding )
{
return ( (DescribedBinding) source ).getDescription();
}
final Class<T> clazz = getImplementationClass();
if ( null != clazz )
{
final Description description = clazz.getAnnotation( Description.class );
if ( null != description )
{
return description.value();
}
final org.sonatype.inject.Description legacy = clazz.getAnnotation( org.sonatype.inject.Description.class );
if ( null != legacy )
{
return legacy.value();
}
}
return null;
}
@SuppressWarnings( "unchecked" )
public Class<T> getImplementationClass()
{
return (Class<T>) binding.acceptTargetVisitor( ImplementationVisitor.THIS );
}
public Object getSource()
{
return InjectorPublisher.getDeclaringSource( binding );
}
public int getRank()
{
return rank;
}
@Override
public String toString()
{
final StringBuilder buf = new StringBuilder().append( getKey() ).append( '=' );
try
{
buf.append( getValue() );
}
catch ( final RuntimeException e )
{
buf.append( e );
}
return buf.toString();
}
// ----------------------------------------------------------------------
// Implementation types
// ----------------------------------------------------------------------
/**
* Implementation of @{@link javax.inject.Named} that can also act like @{@link com.google.inject.name.Named}.
*/
private static final class JsrNamed
implements com.google.inject.name.Named, javax.inject.Named
{
// ----------------------------------------------------------------------
// Implementation fields
// ----------------------------------------------------------------------
private final String value;
// ----------------------------------------------------------------------
// Constructors
// ----------------------------------------------------------------------
JsrNamed( final com.google.inject.name.Named named )
{
value = named.value();
}
// ----------------------------------------------------------------------
// Public methods
// ----------------------------------------------------------------------
public String value()
{
return value;
}
public Class<? extends Annotation> annotationType()
{
return javax.inject.Named.class;
}
@Override
public int hashCode()
{
return 127 * "value".hashCode() ^ value.hashCode();
}
@Override
public boolean equals( final Object rhs )
{
if ( this == rhs )
{
return true;
}
if ( rhs instanceof com.google.inject.name.Named )
{
return value.equals( ( (com.google.inject.name.Named) rhs ).value() );
}
if ( rhs instanceof javax.inject.Named )
{
return value.equals( ( (javax.inject.Named) rhs ).value() );
}
return false;
}
@Override
public String toString()
{
return "@" + javax.inject.Named.class.getName() + "(value=" + value + ")";
}
}
}