/*
* Copyright 2002-2008 the original author or authors.
*
* 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 org.springframework.beans.factory.config;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.JdkVersion;
import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* Descriptor for a specific dependency that is about to be injected.
* Wraps a constructor parameter, a method parameter or a field,
* allowing unified access to their metadata.
*
* @author Juergen Hoeller
* @since 2.5
*/
public class DependencyDescriptor {
private static final Method fieldAnnotationsMethod =
ClassUtils.getMethodIfAvailable(Field.class, "getAnnotations", new Class[0]);
private MethodParameter methodParameter;
private Field field;
private final boolean required;
private final boolean eager;
private Object[] fieldAnnotations;
/**
* Create a new descriptor for a method or constructor parameter.
* Considers the dependency as 'eager'.
* @param methodParameter the MethodParameter to wrap
* @param required whether the dependency is required
*/
public DependencyDescriptor(MethodParameter methodParameter, boolean required) {
this(methodParameter, required, true);
}
/**
* Create a new descriptor for a method or constructor parameter.
* @param methodParameter the MethodParameter to wrap
* @param required whether the dependency is required
* @param eager whether this dependency is 'eager' in the sense of
* eagerly resolving potential target beans for type matching
*/
public DependencyDescriptor(MethodParameter methodParameter, boolean required, boolean eager) {
Assert.notNull(methodParameter, "MethodParameter must not be null");
this.methodParameter = methodParameter;
this.required = required;
this.eager = eager;
}
/**
* Create a new descriptor for a field.
* Considers the dependency as 'eager'.
* @param field the field to wrap
* @param required whether the dependency is required
*/
public DependencyDescriptor(Field field, boolean required) {
this(field, required, true);
}
/**
* Create a new descriptor for a field.
* @param field the field to wrap
* @param required whether the dependency is required
* @param eager whether this dependency is 'eager' in the sense of
* eagerly resolving potential target beans for type matching
*/
public DependencyDescriptor(Field field, boolean required, boolean eager) {
Assert.notNull(field, "Field must not be null");
this.field = field;
this.required = required;
this.eager = eager;
}
/**
* Return the wrapped MethodParameter, if any.
* <p>Note: Either MethodParameter or Field is available.
* @return the MethodParameter, or <code>null</code> if none
*/
public MethodParameter getMethodParameter() {
return this.methodParameter;
}
/**
* Return the wrapped Field, if any.
* <p>Note: Either MethodParameter or Field is available.
* @return the Field, or <code>null</code> if none
*/
public Field getField() {
return this.field;
}
/**
* Return whether this dependency is required.
*/
public boolean isRequired() {
return this.required;
}
/**
* Return whether this dependency is 'eager' in the sense of
* eagerly resolving potential target beans for type matching.
*/
public boolean isEager() {
return this.eager;
}
/**
* Determine the declared (non-generic) type of the wrapped parameter/field.
* @return the declared type (never <code>null</code>)
*/
public Class getDependencyType() {
return (this.field != null ? this.field.getType() : this.methodParameter.getParameterType());
}
/**
* Determine the generic element type of the wrapped Collection parameter/field, if any.
* @return the generic type, or <code>null</code> if none
*/
public Class getCollectionType() {
if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15) {
return null;
}
return (this.field != null ?
GenericCollectionTypeResolver.getCollectionFieldType(this.field) :
GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter));
}
/**
* Determine the generic key type of the wrapped Map parameter/field, if any.
* @return the generic type, or <code>null</code> if none
*/
public Class getMapKeyType() {
if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15) {
return null;
}
return (this.field != null ?
GenericCollectionTypeResolver.getMapKeyFieldType(this.field) :
GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter));
}
/**
* Determine the generic value type of the wrapped Map parameter/field, if any.
* @return the generic type, or <code>null</code> if none
*/
public Class getMapValueType() {
if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15) {
return null;
}
return (this.field != null ?
GenericCollectionTypeResolver.getMapValueFieldType(this.field) :
GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter));
}
/**
* Obtain the annotations associated with the wrapped parameter/field, if any.
* @return the parameter/field annotations, or <code>null</code> if there is
* no annotation support (on JDK < 1.5). The return value is an Object array
* instead of an Annotation array simply for compatibility with older JDKs;
* feel free to cast it to <code>Annotation[]</code> on JDK 1.5 or higher.
*/
public Object[] getAnnotations() {
if (this.field != null) {
if (this.fieldAnnotations != null) {
return this.fieldAnnotations;
}
if (fieldAnnotationsMethod == null) {
return null;
}
this.fieldAnnotations = (Object[]) ReflectionUtils.invokeMethod(fieldAnnotationsMethod, this.field);
return this.fieldAnnotations;
}
else {
return this.methodParameter.getParameterAnnotations();
}
}
}