/******************************************************************************* * Copyright (c) 2010-present 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.space; import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import javax.inject.Provider; import javax.inject.Qualifier; import com.google.inject.Key; import com.google.inject.TypeLiteral; /** * Binding {@link Key} for implementations that act as "wild-cards", meaning they match against any assignable type. * <p> * Since the wild-card type is {@link Object} and the associated qualifier may not be unique between implementations, * the qualifier is saved and replaced with a unique (per-implementation) pseudo-qualifier. The original qualifier is * available by casting the pseudo-qualifier to {@link Provider} and calling {@code get()}. */ final class WildcardKey { // ---------------------------------------------------------------------- // Constants // ---------------------------------------------------------------------- private static final TypeLiteral<Object> OBJECT_TYPE_LITERAL = TypeLiteral.get( Object.class ); // ---------------------------------------------------------------------- // Constructors // ---------------------------------------------------------------------- private WildcardKey() { // static utility class, not allowed to create instances } // ---------------------------------------------------------------------- // Utility methods // ---------------------------------------------------------------------- /** * @return Wildcard key for the given implementation type and qualifier */ public static Key<Object> get( final Class<?> type, final Annotation qualifier ) { return Key.get( OBJECT_TYPE_LITERAL, new QualifiedImpl( type, qualifier ) ); } // ---------------------------------------------------------------------- // Implementation types // ---------------------------------------------------------------------- /** * {@link Qualifier} that captures a qualified implementation type. */ @Qualifier @Retention( RetentionPolicy.RUNTIME ) private static @interface Qualified { Class<?> value(); } /** * Pseudo-{@link Annotation} that can wrap any implementation type as a {@link Qualifier}. */ private static final class QualifiedImpl implements Qualified, Provider<Annotation> { // ---------------------------------------------------------------------- // Implementation fields // ---------------------------------------------------------------------- private final Class<?> value; private final Annotation qualifier; // ---------------------------------------------------------------------- // Constructors // ---------------------------------------------------------------------- QualifiedImpl( final Class<?> value, final Annotation qualifier ) { this.value = value; this.qualifier = qualifier; } // ---------------------------------------------------------------------- // Public methods // ---------------------------------------------------------------------- public Class<?> value() { return value; } public Annotation get() { return qualifier; } public Class<? extends Annotation> annotationType() { return Qualified.class; } @Override public int hashCode() { return value.hashCode(); // no need to follow strict annotation spec } @Override public boolean equals( final Object rhs ) { if ( this == rhs ) { return true; } if ( rhs instanceof QualifiedImpl ) { return value == ( (QualifiedImpl) rhs ).value; } return false; } @Override public String toString() { return "*"; // let people know this is a "wild-card" qualifier } } }