Search in sources :

Example 11 with BeanMetadataElement

use of org.springframework.beans.BeanMetadataElement in project spring-framework by spring-projects.

the class AutowireUtils method resolveReturnTypeForFactoryMethod.

/**
	 * Determine the target type for the generic return type of the given
	 * <em>generic factory method</em>, where formal type variables are declared
	 * on the given method itself.
	 * <p>For example, given a factory method with the following signature, if
	 * {@code resolveReturnTypeForFactoryMethod()} is invoked with the reflected
	 * method for {@code creatProxy()} and an {@code Object[]} array containing
	 * {@code MyService.class}, {@code resolveReturnTypeForFactoryMethod()} will
	 * infer that the target return type is {@code MyService}.
	 * <pre class="code">{@code public static <T> T createProxy(Class<T> clazz)}</pre>
	 * <h4>Possible Return Values</h4>
	 * <ul>
	 * <li>the target return type, if it can be inferred</li>
	 * <li>the {@linkplain Method#getReturnType() standard return type}, if
	 * the given {@code method} does not declare any {@linkplain
	 * Method#getTypeParameters() formal type variables}</li>
	 * <li>the {@linkplain Method#getReturnType() standard return type}, if the
	 * target return type cannot be inferred (e.g., due to type erasure)</li>
	 * <li>{@code null}, if the length of the given arguments array is shorter
	 * than the length of the {@linkplain
	 * Method#getGenericParameterTypes() formal argument list} for the given
	 * method</li>
	 * </ul>
	 * @param method the method to introspect (never {@code null})
	 * @param args the arguments that will be supplied to the method when it is
	 * invoked (never {@code null})
	 * @param classLoader the ClassLoader to resolve class names against,
	 * if necessary (never {@code null})
	 * @return the resolved target return type or the standard method return type
	 * @since 3.2.5
	 */
public static Class<?> resolveReturnTypeForFactoryMethod(Method method, Object[] args, ClassLoader classLoader) {
    Assert.notNull(method, "Method must not be null");
    Assert.notNull(args, "Argument array must not be null");
    Assert.notNull(classLoader, "ClassLoader must not be null");
    TypeVariable<Method>[] declaredTypeVariables = method.getTypeParameters();
    Type genericReturnType = method.getGenericReturnType();
    Type[] methodParameterTypes = method.getGenericParameterTypes();
    Assert.isTrue(args.length == methodParameterTypes.length, "Argument array does not match parameter count");
    // Ensure that the type variable (e.g., T) is declared directly on the method
    // itself (e.g., via <T>), not on the enclosing class or interface.
    boolean locallyDeclaredTypeVariableMatchesReturnType = false;
    for (TypeVariable<Method> currentTypeVariable : declaredTypeVariables) {
        if (currentTypeVariable.equals(genericReturnType)) {
            locallyDeclaredTypeVariableMatchesReturnType = true;
            break;
        }
    }
    if (locallyDeclaredTypeVariableMatchesReturnType) {
        for (int i = 0; i < methodParameterTypes.length; i++) {
            Type methodParameterType = methodParameterTypes[i];
            Object arg = args[i];
            if (methodParameterType.equals(genericReturnType)) {
                if (arg instanceof TypedStringValue) {
                    TypedStringValue typedValue = ((TypedStringValue) arg);
                    if (typedValue.hasTargetType()) {
                        return typedValue.getTargetType();
                    }
                    try {
                        return typedValue.resolveTargetType(classLoader);
                    } catch (ClassNotFoundException ex) {
                        throw new IllegalStateException("Failed to resolve value type [" + typedValue.getTargetTypeName() + "] for factory method argument", ex);
                    }
                }
                // Only consider argument type if it is a simple value...
                if (arg != null && !(arg instanceof BeanMetadataElement)) {
                    return arg.getClass();
                }
                return method.getReturnType();
            } else if (methodParameterType instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) methodParameterType;
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                for (Type typeArg : actualTypeArguments) {
                    if (typeArg.equals(genericReturnType)) {
                        if (arg instanceof Class) {
                            return (Class<?>) arg;
                        } else {
                            String className = null;
                            if (arg instanceof String) {
                                className = (String) arg;
                            } else if (arg instanceof TypedStringValue) {
                                TypedStringValue typedValue = ((TypedStringValue) arg);
                                String targetTypeName = typedValue.getTargetTypeName();
                                if (targetTypeName == null || Class.class.getName().equals(targetTypeName)) {
                                    className = typedValue.getValue();
                                }
                            }
                            if (className != null) {
                                try {
                                    return ClassUtils.forName(className, classLoader);
                                } catch (ClassNotFoundException ex) {
                                    throw new IllegalStateException("Could not resolve class name [" + arg + "] for factory method argument", ex);
                                }
                            }
                            // For now, just fall back...
                            return method.getReturnType();
                        }
                    }
                }
            }
        }
    }
    // Fall back...
    return method.getReturnType();
}
Also used : Method(java.lang.reflect.Method) BeanMetadataElement(org.springframework.beans.BeanMetadataElement) ParameterizedType(java.lang.reflect.ParameterizedType) ParameterizedType(java.lang.reflect.ParameterizedType) Type(java.lang.reflect.Type) TypeVariable(java.lang.reflect.TypeVariable) TypedStringValue(org.springframework.beans.factory.config.TypedStringValue)

Example 12 with BeanMetadataElement

use of org.springframework.beans.BeanMetadataElement in project spring-framework by spring-projects.

the class ConstructorResolver method resolvePreparedArguments.

/**
	 * Resolve the prepared arguments stored in the given bean definition.
	 */
private Object[] resolvePreparedArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw, Executable executable, Object[] argsToResolve) {
    TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
    TypeConverter converter = (customConverter != null ? customConverter : bw);
    BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
    Class<?>[] paramTypes = executable.getParameterTypes();
    Object[] resolvedArgs = new Object[argsToResolve.length];
    for (int argIndex = 0; argIndex < argsToResolve.length; argIndex++) {
        Object argValue = argsToResolve[argIndex];
        MethodParameter methodParam = MethodParameter.forExecutable(executable, argIndex);
        GenericTypeResolver.resolveParameterType(methodParam, executable.getDeclaringClass());
        if (argValue instanceof AutowiredArgumentMarker) {
            argValue = resolveAutowiredArgument(methodParam, beanName, null, converter);
        } else if (argValue instanceof BeanMetadataElement) {
            argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue);
        } else if (argValue instanceof String) {
            argValue = this.beanFactory.evaluateBeanDefinitionString((String) argValue, mbd);
        }
        Class<?> paramType = paramTypes[argIndex];
        try {
            resolvedArgs[argIndex] = converter.convertIfNecessary(argValue, paramType, methodParam);
        } catch (TypeMismatchException ex) {
            throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), "Could not convert argument value of type [" + ObjectUtils.nullSafeClassName(argValue) + "] to required type [" + paramType.getName() + "]: " + ex.getMessage());
        }
    }
    return resolvedArgs;
}
Also used : InjectionPoint(org.springframework.beans.factory.InjectionPoint) TypeMismatchException(org.springframework.beans.TypeMismatchException) InjectionPoint(org.springframework.beans.factory.InjectionPoint) TypeConverter(org.springframework.beans.TypeConverter) BeanMetadataElement(org.springframework.beans.BeanMetadataElement) UnsatisfiedDependencyException(org.springframework.beans.factory.UnsatisfiedDependencyException) MethodParameter(org.springframework.core.MethodParameter)

Example 13 with BeanMetadataElement

use of org.springframework.beans.BeanMetadataElement in project spring-data-mongodb by spring-projects.

the class MappingMongoConverterParser method getCustomConversions.

private BeanDefinition getCustomConversions(Element element, ParserContext parserContext) {
    List<Element> customConvertersElements = DomUtils.getChildElementsByTagName(element, "custom-converters");
    if (customConvertersElements.size() == 1) {
        Element customerConvertersElement = customConvertersElements.get(0);
        ManagedList<BeanMetadataElement> converterBeans = new ManagedList<BeanMetadataElement>();
        List<Element> converterElements = DomUtils.getChildElementsByTagName(customerConvertersElement, "converter");
        if (converterElements != null) {
            for (Element listenerElement : converterElements) {
                converterBeans.add(parseConverter(listenerElement, parserContext));
            }
        }
        // Scan for Converter and GenericConverter beans in the given base-package
        String packageToScan = customerConvertersElement.getAttribute(BASE_PACKAGE);
        if (StringUtils.hasText(packageToScan)) {
            ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
            provider.addExcludeFilter(new NegatingFilter(new AssignableTypeFilter(Converter.class), new AssignableTypeFilter(GenericConverter.class)));
            for (BeanDefinition candidate : provider.findCandidateComponents(packageToScan)) {
                converterBeans.add(candidate);
            }
        }
        BeanDefinitionBuilder conversionsBuilder = BeanDefinitionBuilder.rootBeanDefinition(MongoCustomConversions.class);
        conversionsBuilder.addConstructorArgValue(converterBeans);
        AbstractBeanDefinition conversionsBean = conversionsBuilder.getBeanDefinition();
        conversionsBean.setSource(parserContext.extractSource(element));
        parserContext.registerBeanComponent(new BeanComponentDefinition(conversionsBean, "customConversions"));
        return conversionsBean;
    }
    return null;
}
Also used : AbstractBeanDefinition(org.springframework.beans.factory.support.AbstractBeanDefinition) BeanMetadataElement(org.springframework.beans.BeanMetadataElement) Element(org.w3c.dom.Element) ManagedList(org.springframework.beans.factory.support.ManagedList) RootBeanDefinition(org.springframework.beans.factory.support.RootBeanDefinition) AbstractBeanDefinition(org.springframework.beans.factory.support.AbstractBeanDefinition) BeanDefinition(org.springframework.beans.factory.config.BeanDefinition) GenericBeanDefinition(org.springframework.beans.factory.support.GenericBeanDefinition) BeanMetadataElement(org.springframework.beans.BeanMetadataElement) BeanDefinitionBuilder(org.springframework.beans.factory.support.BeanDefinitionBuilder) ClassPathScanningCandidateComponentProvider(org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider) BeanComponentDefinition(org.springframework.beans.factory.parsing.BeanComponentDefinition) AssignableTypeFilter(org.springframework.core.type.filter.AssignableTypeFilter)

Example 14 with BeanMetadataElement

use of org.springframework.beans.BeanMetadataElement in project spring-data-mongodb by spring-projects.

the class MappingMongoConverterParser method parseConverter.

public BeanMetadataElement parseConverter(Element element, ParserContext parserContext) {
    String converterRef = element.getAttribute("ref");
    if (StringUtils.hasText(converterRef)) {
        return new RuntimeBeanReference(converterRef);
    }
    Element beanElement = DomUtils.getChildElementByTagName(element, "bean");
    if (beanElement != null) {
        BeanDefinitionHolder beanDef = parserContext.getDelegate().parseBeanDefinitionElement(beanElement);
        beanDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(beanElement, beanDef);
        return beanDef;
    }
    parserContext.getReaderContext().error("Element <converter> must specify 'ref' or contain a bean definition for the converter", element);
    return null;
}
Also used : BeanMetadataElement(org.springframework.beans.BeanMetadataElement) Element(org.w3c.dom.Element) BeanDefinitionHolder(org.springframework.beans.factory.config.BeanDefinitionHolder) RuntimeBeanReference(org.springframework.beans.factory.config.RuntimeBeanReference)

Example 15 with BeanMetadataElement

use of org.springframework.beans.BeanMetadataElement in project spring-framework by spring-projects.

the class DatabasePopulatorConfigUtils method createDatabasePopulator.

private static BeanDefinition createDatabasePopulator(Element element, List<Element> scripts, String execution) {
    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CompositeDatabasePopulator.class);
    boolean ignoreFailedDrops = element.getAttribute("ignore-failures").equals("DROPS");
    boolean continueOnError = element.getAttribute("ignore-failures").equals("ALL");
    ManagedList<BeanMetadataElement> delegates = new ManagedList<>();
    for (Element scriptElement : scripts) {
        String executionAttr = scriptElement.getAttribute("execution");
        if (!StringUtils.hasText(executionAttr)) {
            executionAttr = "INIT";
        }
        if (!execution.equals(executionAttr)) {
            continue;
        }
        BeanDefinitionBuilder delegate = BeanDefinitionBuilder.genericBeanDefinition(ResourceDatabasePopulator.class);
        delegate.addPropertyValue("ignoreFailedDrops", ignoreFailedDrops);
        delegate.addPropertyValue("continueOnError", continueOnError);
        // Use a factory bean for the resources so they can be given an order if a pattern is used
        BeanDefinitionBuilder resourcesFactory = BeanDefinitionBuilder.genericBeanDefinition(SortedResourcesFactoryBean.class);
        resourcesFactory.addConstructorArgValue(new TypedStringValue(scriptElement.getAttribute("location")));
        delegate.addPropertyValue("scripts", resourcesFactory.getBeanDefinition());
        if (StringUtils.hasLength(scriptElement.getAttribute("encoding"))) {
            delegate.addPropertyValue("sqlScriptEncoding", new TypedStringValue(scriptElement.getAttribute("encoding")));
        }
        String separator = getSeparator(element, scriptElement);
        if (separator != null) {
            delegate.addPropertyValue("separator", new TypedStringValue(separator));
        }
        delegates.add(delegate.getBeanDefinition());
    }
    builder.addPropertyValue("populators", delegates);
    return builder.getBeanDefinition();
}
Also used : BeanMetadataElement(org.springframework.beans.BeanMetadataElement) BeanDefinitionBuilder(org.springframework.beans.factory.support.BeanDefinitionBuilder) BeanMetadataElement(org.springframework.beans.BeanMetadataElement) Element(org.w3c.dom.Element) ManagedList(org.springframework.beans.factory.support.ManagedList) TypedStringValue(org.springframework.beans.factory.config.TypedStringValue)

Aggregations

BeanMetadataElement (org.springframework.beans.BeanMetadataElement)25 BeanDefinitionBuilder (org.springframework.beans.factory.support.BeanDefinitionBuilder)17 RuntimeBeanReference (org.springframework.beans.factory.config.RuntimeBeanReference)16 Element (org.w3c.dom.Element)16 BeanDefinition (org.springframework.beans.factory.config.BeanDefinition)11 RootBeanDefinition (org.springframework.beans.factory.support.RootBeanDefinition)9 ManagedList (org.springframework.beans.factory.support.ManagedList)8 BeanComponentDefinition (org.springframework.beans.factory.parsing.BeanComponentDefinition)5 ManagedMap (org.springframework.beans.factory.support.ManagedMap)5 TypedStringValue (org.springframework.beans.factory.config.TypedStringValue)3 Method (java.lang.reflect.Method)2 BeanReference (org.springframework.beans.factory.config.BeanReference)2 CompositeComponentDefinition (org.springframework.beans.factory.parsing.CompositeComponentDefinition)2 ParameterizedType (java.lang.reflect.ParameterizedType)1 Type (java.lang.reflect.Type)1 TypeVariable (java.lang.reflect.TypeVariable)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1 TypeConverter (org.springframework.beans.TypeConverter)1 TypeMismatchException (org.springframework.beans.TypeMismatchException)1