/* * Copyright (C) 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.inject.assistedinject; import static com.google.common.base.Preconditions.checkArgument; import com.google.inject.ConfigurationException; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Provider; import com.google.inject.internal.Annotations; import java.lang.annotation.Annotation; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; /** * Models a method or constructor parameter. * * @author jmourits@google.com (Jerome Mourits) * @author jessewilson@google.com (Jesse Wilson) */ class Parameter { private final Type type; private final boolean isAssisted; private final Annotation bindingAnnotation; private final boolean isProvider; private volatile Provider<? extends Object> provider; public Parameter(Type type, Annotation[] annotations) { this.type = type; this.bindingAnnotation = getBindingAnnotation(annotations); this.isAssisted = hasAssistedAnnotation(annotations); this.isProvider = isProvider(type); } public boolean isProvidedByFactory() { return isAssisted; } public Type getType() { return type; } @Override public String toString() { StringBuilder result = new StringBuilder(); if (isAssisted) { result.append("@Assisted "); } if (bindingAnnotation != null) { result.append(bindingAnnotation).append(" "); } return result.append(type).toString(); } private boolean hasAssistedAnnotation(Annotation[] annotations) { for (Annotation annotation : annotations) { if (annotation.annotationType().equals(Assisted.class)) { return true; } } return false; } /** Returns the Guice {@link Key} for this parameter. */ public Object getValue(Injector injector) { if (null == provider) { synchronized (this) { if (null == provider) { provider = isProvider ? injector.getProvider(getBindingForType(getProvidedType(type))) : injector.getProvider(getPrimaryBindingKey()); } } } return isProvider ? provider : provider.get(); } public boolean isBound(Injector injector) { return isBound(injector, getPrimaryBindingKey()) || isBound(injector, fixAnnotations(getPrimaryBindingKey())); } private boolean isBound(Injector injector, Key<?> key) { // This method is particularly lame - we really need an API that can test // for any binding, implicit or explicit try { return injector.getBinding(key) != null; } catch (ConfigurationException e) { return false; } } /** * Replace annotation instances with annotation types, this is only appropriate for testing if a * key is bound and not for injecting. * * <p>See Guice bug 125, https://github.com/google/guice/issues/125 */ public Key<?> fixAnnotations(Key<?> key) { return key.getAnnotation() == null ? key : Key.get(key.getTypeLiteral(), key.getAnnotation().annotationType()); } Key<?> getPrimaryBindingKey() { return isProvider ? getBindingForType(getProvidedType(type)) : getBindingForType(type); } private Type getProvidedType(Type type) { return ((ParameterizedType) type).getActualTypeArguments()[0]; } private boolean isProvider(Type type) { return type instanceof ParameterizedType && ((ParameterizedType) type).getRawType() == Provider.class; } private Key<?> getBindingForType(Type type) { return bindingAnnotation != null ? Key.get(type, bindingAnnotation) : Key.get(type); } /** * Returns the unique binding annotation from the specified list, or {@code null} if there are * none. * * @throws IllegalStateException if multiple binding annotations exist. */ private Annotation getBindingAnnotation(Annotation[] annotations) { Annotation bindingAnnotation = null; for (Annotation annotation : annotations) { if (Annotations.isBindingAnnotation(annotation.annotationType())) { checkArgument( bindingAnnotation == null, "Parameter has multiple binding annotations: %s and %s", bindingAnnotation, annotation); bindingAnnotation = annotation; } } return bindingAnnotation; } }