001: /*
002: * Copyright 2002-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.beans.factory.support;
018:
019: import java.beans.PropertyDescriptor;
020: import java.lang.reflect.Constructor;
021: import java.lang.reflect.Method;
022: import java.lang.reflect.Modifier;
023: import java.util.Arrays;
024: import java.util.Comparator;
025: import java.util.Iterator;
026: import java.util.Set;
027:
028: import org.springframework.util.ClassUtils;
029:
030: /**
031: * Utility class that contains various methods useful for
032: * the implementation of autowire-capable bean factories.
033: *
034: * @author Juergen Hoeller
035: * @since 1.1.2
036: * @see AbstractAutowireCapableBeanFactory
037: */
038: abstract class AutowireUtils {
039:
040: /**
041: * Sort the given constructors, preferring public constructors and "greedy" ones
042: * with a maximum of arguments. The result will contain public constructors first,
043: * with decreasing number of arguments, then non-public constructors, again with
044: * decreasing number of arguments.
045: * @param constructors the constructor array to sort
046: */
047: public static void sortConstructors(Constructor[] constructors) {
048: Arrays.sort(constructors, new Comparator() {
049: public int compare(Object o1, Object o2) {
050: Constructor c1 = (Constructor) o1;
051: Constructor c2 = (Constructor) o2;
052: boolean p1 = Modifier.isPublic(c1.getModifiers());
053: boolean p2 = Modifier.isPublic(c2.getModifiers());
054: if (p1 != p2) {
055: return (p1 ? -1 : 1);
056: }
057: int c1pl = c1.getParameterTypes().length;
058: int c2pl = c2.getParameterTypes().length;
059: return (new Integer(c1pl)).compareTo(new Integer(c2pl))
060: * -1;
061: }
062: });
063: }
064:
065: /**
066: * Determine a weight that represents the class hierarchy difference between types and
067: * arguments. A direct match, i.e. type Integer -> arg of class Integer, does not increase
068: * the result - all direct matches means weight 0. A match between type Object and arg of
069: * class Integer would increase the weight by 2, due to the superclass 2 steps up in the
070: * hierarchy (i.e. Object) being the last one that still matches the required type Object.
071: * Type Number and class Integer would increase the weight by 1 accordingly, due to the
072: * superclass 1 step up the hierarchy (i.e. Number) still matching the required type Number.
073: * Therefore, with an arg of type Integer, a constructor (Integer) would be preferred to a
074: * constructor (Number) which would in turn be preferred to a constructor (Object).
075: * All argument weights get accumulated.
076: * @param paramTypes the parameter types to match
077: * @param args the arguments to match
078: * @return the accumulated weight for all arguments
079: */
080: public static int getTypeDifferenceWeight(Class[] paramTypes,
081: Object[] args) {
082: int result = 0;
083: for (int i = 0; i < paramTypes.length; i++) {
084: if (!ClassUtils.isAssignableValue(paramTypes[i], args[i])) {
085: return Integer.MAX_VALUE;
086: }
087: if (args[i] != null) {
088: Class super Class = args[i].getClass().getSuperclass();
089: while (super Class != null) {
090: if (ClassUtils.isAssignable(paramTypes[i],
091: super Class)) {
092: result++;
093: super Class = super Class.getSuperclass();
094: } else {
095: super Class = null;
096: }
097: }
098: }
099: }
100: return result;
101: }
102:
103: /**
104: * Determine whether the given bean property is excluded from dependency checks.
105: * <p>This implementation excludes properties defined by CGLIB.
106: * @param pd the PropertyDescriptor of the bean property
107: * @return whether the bean property is excluded
108: */
109: public static boolean isExcludedFromDependencyCheck(
110: PropertyDescriptor pd) {
111: Method wm = pd.getWriteMethod();
112: if (wm == null) {
113: return false;
114: }
115: if (wm.getDeclaringClass().getName().indexOf("$$") == -1) {
116: // Not a CGLIB method so it's OK.
117: return false;
118: }
119: // It was declared by CGLIB, but we might still want to autowire it
120: // if it was actually declared by the superclass.
121: Class super class = wm.getDeclaringClass().getSuperclass();
122: return !ClassUtils.hasMethod(super class, wm.getName(), wm
123: .getParameterTypes());
124: }
125:
126: /**
127: * Return whether the setter method of the given bean property is defined
128: * in any of the given interfaces.
129: * @param pd the PropertyDescriptor of the bean property
130: * @param interfaces the Set of interfaces (Class objects)
131: * @return whether the setter method is defined by an interface
132: */
133: public static boolean isSetterDefinedInInterface(
134: PropertyDescriptor pd, Set interfaces) {
135: Method setter = pd.getWriteMethod();
136: if (setter != null) {
137: Class targetClass = setter.getDeclaringClass();
138: for (Iterator it = interfaces.iterator(); it.hasNext();) {
139: Class ifc = (Class) it.next();
140: if (ifc.isAssignableFrom(targetClass)
141: && ClassUtils.hasMethod(ifc, setter.getName(),
142: setter.getParameterTypes())) {
143: return true;
144: }
145: }
146: }
147: return false;
148: }
149:
150: }
|