All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.datalking.beans.factory.config.DependencyDescriptor Maven / Gradle / Ivy

package com.github.datalking.beans.factory.config;

import com.github.datalking.beans.factory.BeanFactory;
import com.github.datalking.common.GenericCollectionTypeResolver;
import com.github.datalking.common.MethodParameter;
import com.github.datalking.common.ParameterNameDiscoverer;
import com.github.datalking.util.Assert;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * 依赖项的描述对象
 * 如A依赖B,则表示B的描述信息
 * 封装构造方法参数、普通方法参数或成员字段
 *
 * @author yaoo on 5/28/18
 */
public class DependencyDescriptor implements Serializable {

    private transient MethodParameter methodParameter;

    // 字段对象,一般是B的对象
    private transient Field field;

    // 字段名,一般是B的名称
    private String fieldName;

    // 外层类class对象,一般是A
    private Class declaringClass;

    private String methodName;

    private Class[] parameterTypes;

    private int parameterIndex;

    private final boolean required;

    private final boolean eager;

    private int nestingLevel = 1;

    private transient Annotation[] fieldAnnotations;

    public DependencyDescriptor(MethodParameter methodParameter, boolean required) {
        this(methodParameter, required, true);
    }

    public DependencyDescriptor(MethodParameter methodParameter, boolean required, boolean eager) {
        Assert.notNull(methodParameter, "MethodParameter must not be null");
        this.methodParameter = methodParameter;
        this.declaringClass = methodParameter.getDeclaringClass();
        if (this.methodParameter.getMethod() != null) {
            this.methodName = methodParameter.getMethod().getName();
            this.parameterTypes = methodParameter.getMethod().getParameterTypes();
        } else {
            this.parameterTypes = methodParameter.getConstructor().getParameterTypes();
        }
        this.parameterIndex = methodParameter.getParameterIndex();
        this.required = required;
        this.eager = eager;
    }

    public DependencyDescriptor(Field field, boolean required) {
        this(field, required, true);
    }

    public DependencyDescriptor(Field field, boolean required, boolean eager) {
        Assert.notNull(field, "Field must not be null");
        this.field = field;
        this.declaringClass = field.getDeclaringClass();
        this.fieldName = field.getName();
        this.required = required;
        this.eager = eager;
    }

    public DependencyDescriptor(DependencyDescriptor original) {
        this.methodParameter = (original.methodParameter != null ? new MethodParameter(original.methodParameter) : null);
        this.field = original.field;
        this.declaringClass = original.declaringClass;
        this.methodName = original.methodName;
        this.parameterTypes = original.parameterTypes;
        this.parameterIndex = original.parameterIndex;
        this.fieldName = original.fieldName;
        this.required = original.required;
        this.eager = original.eager;
        this.nestingLevel = original.nestingLevel;
        this.fieldAnnotations = original.fieldAnnotations;
    }


    /**
     * Return the wrapped MethodParameter, if any.
     * 

Note: Either MethodParameter or Field is available. * * @return the MethodParameter, or {@code null} if none */ public MethodParameter getMethodParameter() { return this.methodParameter; } /** * Return the wrapped Field, if any. *

Note: Either MethodParameter or Field is available. * * @return the Field, or {@code null} 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; } /** * Increase this descriptor's nesting level. * * @see MethodParameter#increaseNestingLevel() */ public void increaseNestingLevel() { this.nestingLevel++; if (this.methodParameter != null) { this.methodParameter.increaseNestingLevel(); } } /** * Initialize parameter name discovery for the underlying method parameter, if any. *

This method does not actually try to retrieve the parameter name at * this point; it just allows discovery to happen when the application calls * {@link #getDependencyName()} (if ever). */ public void initParameterNameDiscovery(ParameterNameDiscoverer parameterNameDiscoverer) { if (this.methodParameter != null) { this.methodParameter.initParameterNameDiscovery(parameterNameDiscoverer); } } /** * Determine the name of the wrapped parameter/field. * * @return the declared name (never {@code null}) */ public String getDependencyName() { return (this.field != null ? this.field.getName() : this.methodParameter.getParameterName()); } /** * Determine the declared (non-generic) type of the wrapped parameter/field. * * @return the declared type (never {@code null}) */ public Class getDependencyType() { if (this.field != null) { if (this.nestingLevel > 1) { Type type = this.field.getGenericType(); if (type instanceof ParameterizedType) { Type arg = ((ParameterizedType) type).getActualTypeArguments()[0]; if (arg instanceof Class) { return (Class) arg; } else if (arg instanceof ParameterizedType) { arg = ((ParameterizedType) arg).getRawType(); if (arg instanceof Class) { return (Class) arg; } } } return Object.class; } else { return this.field.getType(); } } else { return this.methodParameter.getNestedParameterType(); } } /** * Determine the generic element type of the wrapped Collection parameter/field, if any. * * @return the generic type, or {@code null} if none */ public Class getCollectionType() { return (this.field != null ? GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel) : GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter)); } /** * Determine the generic key type of the wrapped Map parameter/field, if any. * * @return the generic type, or {@code null} if none */ public Class getMapKeyType() { return (this.field != null ? GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel) : GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter)); } /** * Determine the generic value type of the wrapped Map parameter/field, if any. * * @return the generic type, or {@code null} if none */ public Class getMapValueType() { return (this.field != null ? GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel) : GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter)); } /** * Obtain the annotations associated with the wrapped parameter/field, if any. */ public Annotation[] getAnnotations() { if (this.field != null) { if (this.fieldAnnotations == null) { this.fieldAnnotations = this.field.getAnnotations(); } return this.fieldAnnotations; } else { return this.methodParameter.getParameterAnnotations(); } } //--------------------------------------------------------------------- // Serialization support //--------------------------------------------------------------------- private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { // Rely on default serialization; just initialize state after deserialization. ois.defaultReadObject(); // Restore reflective handles (which are unfortunately not serializable) try { if (this.fieldName != null) { this.field = this.declaringClass.getDeclaredField(this.fieldName); } else { if (this.methodName != null) { this.methodParameter = new MethodParameter( this.declaringClass.getDeclaredMethod(this.methodName, this.parameterTypes), this.parameterIndex); } else { this.methodParameter = new MethodParameter( this.declaringClass.getDeclaredConstructor(this.parameterTypes), this.parameterIndex); } for (int i = 1; i < this.nestingLevel; i++) { this.methodParameter.increaseNestingLevel(); } } } catch (Throwable ex) { throw new IllegalStateException("Could not find original class structure", ex); } } public Object resolveCandidate(String beanName, Class requiredType, BeanFactory beanFactory) { return beanFactory.getBean(beanName); } @Override public String toString() { return (this.field != null ? "field '" + this.field.getName() + "'" : this.methodParameter.toString()); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy