| /******************************************************************************* |
| * Copyright (c) 2004, 2005 Sybase, Inc. and others. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Sybase, Inc. - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jst.jsf.facesconfig.ui.util; |
| |
| import java.beans.Introspector; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.jdt.core.IMethod; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.ITypeHierarchy; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.Signature; |
| import org.eclipse.jst.jsf.common.ui.internal.utils.JavaModelUtil; |
| |
| /** |
| * This utility class is used to access java bean class, e.g., get java bean's |
| * property |
| * |
| * @author xgzhang |
| * @version |
| */ |
| public final class JavaBeanUtils { |
| /** |
| * fully qualified name of a List |
| */ |
| private static final String JAVA_UTIL_LIST = "java.util.List"; //$NON-NLS-1$ |
| |
| /** |
| * fully qualifed name of a Map |
| */ |
| private static final String JAVA_UTIL_MAP = "java.util.Map"; //$NON-NLS-1$ |
| |
| /** |
| * |
| */ |
| private JavaBeanUtils() { |
| super(); |
| } |
| |
| /** |
| * get the getter method according to property name |
| * |
| * @param type |
| * @param propertyName |
| * @return - can be <b>null</b>, if not found |
| * @throws JavaModelException |
| * @throws JavaModelException |
| */ |
| private static IMethod getPropertyGetterMethod(IType type, |
| String propertyName) { |
| if (type == null || !type.exists() || propertyName == null) { |
| return null; |
| } |
| IMethod getterMethod = null; |
| |
| String methodBaseName = null; |
| // Uppercase 1st letter |
| if (propertyName.length() == 1) { |
| methodBaseName = propertyName.substring(0, 1).toUpperCase(); |
| } else { |
| methodBaseName = propertyName.substring(0, 1).toUpperCase() |
| + propertyName.substring(1); |
| } |
| |
| String getterMethodName = "get" + methodBaseName; //$NON-NLS-1$ |
| |
| getterMethod = type.getMethod(getterMethodName, null); |
| if (getterMethod == null || !getterMethod.exists() |
| || !JavaClassUtils.isPublicMethod(getterMethod)) { |
| getterMethodName = "is" + methodBaseName; //$NON-NLS-1$ |
| getterMethod = type.getMethod(getterMethodName, null); |
| |
| if (getterMethod == null || !getterMethod.exists() |
| || !JavaClassUtils.isPublicMethod(getterMethod)) { |
| getterMethod = null; |
| } |
| } |
| return getterMethod; |
| } |
| |
| /** |
| * get the getter method in the type hierarchy according to property name |
| * |
| * @param type |
| * @param propertyName |
| * @return - can be <b>null</b>, if not found |
| * @throws JavaModelException |
| * @throws JavaModelException |
| */ |
| private static IMethod getPropertyGetterMethodInTypeHierarchy(IType type, |
| String propertyName) throws JavaModelException { |
| if (type == null || !type.exists() || propertyName == null) { |
| return null; |
| } |
| IMethod getterMethod = null; |
| |
| getterMethod = getPropertyGetterMethod(type, propertyName); |
| |
| if (getterMethod == null) { |
| ITypeHierarchy typeHierarchy = null; |
| typeHierarchy = type.newSupertypeHierarchy(null); |
| |
| if (typeHierarchy == null) { |
| return null; |
| } |
| |
| IType[] superTypes = typeHierarchy.getAllSuperclasses(type); |
| |
| if (superTypes == null || superTypes.length == 0) { |
| return null; |
| } |
| for (int i = 0; i < superTypes.length; i++) { |
| if (!superTypes[i].getFullyQualifiedName().equals( |
| "java.lang.Object")) { //$NON-NLS-1$ |
| getterMethod = getPropertyGetterMethod(superTypes[i], |
| propertyName); |
| if (getterMethod != null) { |
| break; |
| } |
| } |
| } |
| } |
| return getterMethod; |
| } |
| |
| /** |
| * get the setter method in the type hierarchy according to property name |
| * |
| * @param type |
| * @param propertyName |
| * @return - can be <b>null</b>, if not found |
| * @throws JavaModelException |
| */ |
| private static IMethod getPropertySetterMethodInTypeHierarchy(IType type, |
| String propertyName) throws JavaModelException { |
| if (type == null || !type.exists() || propertyName == null) { |
| return null; |
| } |
| IMethod setterMethod = null; |
| |
| setterMethod = getPropertySetterMethod(type, propertyName); |
| |
| if (setterMethod == null) { |
| ITypeHierarchy typeHierarchy = null; |
| typeHierarchy = type.newSupertypeHierarchy(null); |
| |
| if (typeHierarchy == null) { |
| return null; |
| } |
| |
| IType[] superTypes = typeHierarchy.getAllSuperclasses(type); |
| |
| if (superTypes == null || superTypes.length == 0) { |
| return null; |
| } |
| for (int i = 0; i < superTypes.length; i++) { |
| if (!superTypes[i].getFullyQualifiedName().equals( |
| "java.lang.Object")) { //$NON-NLS-1$ |
| setterMethod = getPropertySetterMethod(superTypes[i], |
| propertyName); |
| if (setterMethod != null) { |
| break; |
| } |
| } |
| } |
| } |
| |
| return setterMethod; |
| } |
| |
| /** |
| * get the setter method according to property name |
| * |
| * @param type |
| * @param propertyName |
| * @return - can be <b>null</b>, if not found |
| * @throws JavaModelException |
| */ |
| private static IMethod getPropertySetterMethod(IType type, |
| String propertyName) throws JavaModelException { |
| if (type == null || !type.exists() || propertyName == null) { |
| return null; |
| } |
| IMethod setterMethod = null; |
| |
| String methodBaseName = null; |
| // Uppercase 1st letter |
| if (propertyName.length() == 1) { |
| methodBaseName = propertyName.substring(0, 1).toUpperCase(); |
| } else { |
| methodBaseName = propertyName.substring(0, 1).toUpperCase() |
| + propertyName.substring(1); |
| } |
| |
| String setterMethodName = "set" + methodBaseName; //$NON-NLS-1$ |
| |
| IMethod[] methods = null; |
| |
| methods = type.getMethods(); |
| |
| if (methods == null || methods.length == 0) { |
| return null; |
| } |
| |
| for (int i = 0; i < methods.length; i++) { |
| if (methods[i].getElementName().equals(setterMethodName)) { |
| if (methods[i] == null || !methods[i].exists() |
| || !JavaClassUtils.isPublicMethod(methods[i])) { |
| continue; |
| } |
| |
| // Method must return void |
| String returnType = methods[i].getReturnType(); |
| if (!returnType.equals(Signature.SIG_VOID)) { |
| continue; |
| } |
| |
| String params[] = methods[i].getParameterTypes(); |
| // method must have only one argument |
| if (params.length != 1) { |
| continue; |
| } |
| setterMethod = methods[i]; |
| } |
| } |
| |
| return setterMethod; |
| } |
| |
| /** |
| * Check whether the propertyName is bean's property or not. |
| * |
| * @param baseType |
| * @param propertyName |
| * |
| * @return - True means the property name is valid bean's property, |
| * otherwise, not. |
| * |
| */ |
| public static boolean isBeanProperty(IType baseType, String propertyName) |
| { |
| if (baseType == null || !baseType.exists() || propertyName == null) { |
| return false; |
| } |
| |
| return (getBeanPropertyType(baseType, propertyName) != null); |
| } |
| |
| /** |
| * get the bean's property type |
| * |
| * @param baseType |
| * @param propertyName |
| * @return - can be <b>null</b>, if not found |
| * |
| */ |
| public static IType getBeanPropertyType(IType baseType, String propertyName) { |
| if (baseType == null || !baseType.exists() || propertyName == null) { |
| return null; |
| } |
| |
| String typeSignature = null; |
| IMethod getterMethod = null; |
| IMethod setterMethod = null; |
| |
| IType declaredType = baseType; |
| try { |
| getterMethod = getPropertyGetterMethodInTypeHierarchy(baseType, |
| propertyName); |
| setterMethod = getPropertySetterMethodInTypeHierarchy(baseType, |
| propertyName); |
| } catch (JavaModelException e1) { |
| // Need not any error handling. |
| } |
| |
| if (getterMethod != null && setterMethod == null) { |
| declaredType = getterMethod.getDeclaringType(); |
| try { |
| typeSignature = getterMethod.getReturnType(); |
| } catch (JavaModelException e2) { |
| // Need not any error handling. |
| } |
| } else if (setterMethod != null && getterMethod == null) { |
| declaredType = setterMethod.getDeclaringType(); |
| typeSignature = setterMethod.getParameterTypes()[0]; |
| } else if (setterMethod != null && getterMethod != null) { |
| declaredType = getterMethod.getDeclaringType(); |
| try { |
| // FIXME: should check the type hierachy |
| if (getterMethod.getReturnType().equals( |
| setterMethod.getParameterTypes()[0])) { |
| typeSignature = getterMethod.getReturnType(); |
| } |
| } catch (JavaModelException e2) { |
| // Need not any error handling. |
| } |
| } |
| |
| if (typeSignature == null) { |
| return null; |
| } |
| |
| IType type = null; |
| |
| try { |
| String typeName = JavaModelUtil.getResolvedTypeName(typeSignature, |
| declaredType); |
| if (typeName != null) { |
| type = baseType.getJavaProject().findType(typeName); |
| } |
| } catch (JavaModelException e) { |
| // Need not any error handling. |
| } |
| return type; |
| } |
| |
| /** |
| * get the bean's property's getter and setter methods. |
| * |
| * @param baseType |
| * @param propertyName |
| * @return - IMethod[], the first is getter and the second is setter method, |
| * however, both of them can be null. |
| */ |
| public static IMethod[] getBeanPropertyMethods(IType baseType, |
| String propertyName) { |
| if (baseType == null || !baseType.exists() || propertyName == null) { |
| return null; |
| } |
| |
| IMethod[] methods = new IMethod[2]; |
| |
| IMethod getterMethod = null; |
| IMethod setterMethod = null; |
| try { |
| getterMethod = getPropertyGetterMethodInTypeHierarchy(baseType, |
| propertyName); |
| |
| setterMethod = getPropertySetterMethodInTypeHierarchy(baseType, |
| propertyName); |
| } catch (JavaModelException e) { |
| // Need not any error handling. |
| } |
| |
| if (getterMethod != null && setterMethod == null) { |
| methods[0] = getterMethod; |
| } else if (setterMethod != null && getterMethod == null) { |
| methods[1] = setterMethod; |
| } else if (setterMethod != null && getterMethod != null) { |
| try { |
| // FIXME: should check the type hierachy |
| if (getterMethod.getReturnType().equals( |
| setterMethod.getParameterTypes()[0])) { |
| methods[0] = getterMethod; |
| methods[1] = setterMethod; |
| } |
| } catch (JavaModelException e1) { |
| // Need not any error handling. |
| } |
| } |
| |
| return methods; |
| } |
| |
| /** |
| * check whether the type implements <code>java.util.List</code> |
| * |
| * @param type |
| * @return - True if the type is the sub class of |
| * <code>java.util.List</code>, otherwise, not. |
| */ |
| public static boolean isListType(IType type) { |
| if (type == null) { |
| return false; |
| } |
| if (type.getFullyQualifiedName().equalsIgnoreCase(JAVA_UTIL_LIST)) { |
| return true; |
| } |
| |
| return JavaClassUtils.isSubClassOf(type.getJavaProject(), type |
| .getFullyQualifiedName(), JAVA_UTIL_LIST); |
| } |
| |
| /** |
| * check whether the type implements <code>java.util.Map</code> |
| * |
| * @param type |
| * @return - True if the type is the sub class of <code>java.uitl.Map</code>, |
| * otherwise, not. |
| */ |
| public static boolean isMapType(IType type) { |
| if (type == null) { |
| return false; |
| } |
| if (type.getFullyQualifiedName().equalsIgnoreCase(JAVA_UTIL_MAP)) { |
| return true; |
| } |
| |
| return JavaClassUtils.isSubClassOf(type.getJavaProject(), type |
| .getFullyQualifiedName(), JAVA_UTIL_MAP); |
| } |
| |
| /** |
| * Test for method inclusion in bindings list. |
| * <p> |
| * This test has the following conditions: |
| * </p> |
| * <ul> |
| * <li>method starts with <code>get</code></li> |
| * <li>method has no arguments</li> |
| * <li>method does not return void</li> |
| * </ul> |
| * |
| * @param method - |
| * the IMethod to examine |
| * @return boolean - true, if method satisfies the condition test |
| */ |
| public static boolean isGetterMethod(IMethod method) { |
| try { |
| if (!JavaClassUtils.isPublicMethod(method)) { |
| return false; |
| } |
| String params[] = method.getParameterTypes(); |
| // Has no arguments |
| if (params.length > 0) { |
| return false; |
| } |
| |
| // Starts with "get" |
| if (!(method.getElementName().startsWith("get") || method.getElementName().startsWith("is"))) //$NON-NLS-1$ //$NON-NLS-2$ |
| { |
| return false; |
| } |
| // Does not return void |
| String rtn = method.getReturnType(); |
| if (!rtn.equals(Signature.SIG_VOID)) { |
| return true; |
| } |
| } catch (JavaModelException e) { |
| // Need not any error handling. |
| } |
| return false; |
| } |
| |
| /** |
| * Test for method inclusion in bindings list. |
| * <p> |
| * This test has the following conditions: |
| * </p> |
| * <ul> |
| * <li>method starts with <code>set</code></li> |
| * <li>method returns void</li> |
| * </ul> |
| * |
| * @param method - |
| * the IMethod to examine |
| * @return boolean - true, if method satisfies the condition test |
| */ |
| public static boolean isSetterMethod(IMethod method) { |
| try { |
| if (!JavaClassUtils.isPublicMethod(method)) { |
| return false; |
| } |
| // Starts with "set" |
| if (!method.getElementName().startsWith("set")) //$NON-NLS-1$ |
| { |
| return false; |
| } |
| |
| // the parameter's number should be one. |
| if (method.getParameterTypes().length != 1) { |
| return false; |
| } |
| // Returns void |
| String rtn = method.getReturnType(); |
| if (rtn.equals(Signature.SIG_VOID)) { |
| return true; |
| } |
| } catch (JavaModelException e) { |
| // Need not any error handling. |
| } |
| return false; |
| } |
| |
| /** |
| * set the first character into low case. |
| * |
| * @param str |
| * @return str with the first char lower cased |
| */ |
| public static String toLowCaseFirstChar(String str) { |
| // change the first alphabet to lowcase. |
| if (str != null && str.length() > 0) { |
| if (str.length() == 1) { |
| str = str.toLowerCase(); |
| } else { |
| str = str.substring(0, 1).toLowerCase() + str.substring(1); |
| } |
| } |
| return str; |
| } |
| |
| /** |
| * set the first character into low case. |
| * |
| * @param str |
| * @return str with the first char upper-cased |
| */ |
| public static String toUpperCaseFirstChar(String str) { |
| // change the first alphabet to lowcase. |
| if (str != null && str.length() > 0) { |
| if (str.length() == 1) { |
| str = str.toUpperCase(); |
| } else { |
| str = str.substring(0, 1).toUpperCase() + str.substring(1); |
| } |
| } |
| return str; |
| } |
| |
| /** |
| * get property name from getter method. |
| * |
| * @param method |
| * @return - can be <b>null</b>, if the method is not a valid getter method |
| */ |
| public static String getPropertyNameFromGetterMethod(IMethod method) { |
| if (!isGetterMethod(method)) { |
| return null; |
| } |
| String methodName = method.getElementName(); |
| String propertyName = null; |
| // Starts with "get" |
| if (methodName.startsWith("get") && methodName.length() > 3) { //$NON-NLS-1$ |
| propertyName = methodName.substring(3); |
| } else if (methodName.startsWith("is") && methodName.length() > 2) // Starts //$NON-NLS-1$ |
| // with |
| // "is" |
| { |
| propertyName = methodName.substring(2); |
| } |
| propertyName = Introspector.decapitalize(propertyName); |
| return propertyName; |
| } |
| |
| /** |
| * get property name from setter class. |
| * |
| * @param method |
| * @return - can be <b>null</b>, if the method is not a valid setter method |
| */ |
| public static String getPropertyNameFromSetterMethod(IMethod method) { |
| if (!isSetterMethod(method)) { |
| return null; |
| } |
| String methodName = method.getElementName(); |
| String propertyName = null; |
| // Starts with "get" |
| if (methodName.startsWith("set") && methodName.length() > 3) { //$NON-NLS-1$ |
| propertyName = methodName.substring(3); |
| } |
| propertyName = Introspector.decapitalize(propertyName); |
| return propertyName; |
| } |
| |
| /** |
| * get the method with the same parameters |
| * |
| * @param methods |
| * @param visitedMethods |
| * @param foundMethod |
| * @param foundMethodName |
| * @param foundParamTypes |
| * @return |
| */ |
| private static IMethod getMethodWithSameParamters(IMethod[] methods, |
| Map visitedMethods, IMethod foundMethod, String foundMethodName, |
| String[] foundParamTypes) { |
| // get all qualified type name for the found method's parameters. |
| String[] foundParamQulifiedTypeNames = null; |
| if (foundParamTypes != null && foundParamTypes.length > 0) { |
| foundParamQulifiedTypeNames = new String[foundParamTypes.length]; |
| for (int i = 0; i < foundParamTypes.length; i++) { |
| foundParamQulifiedTypeNames[i] = JavaClassUtils |
| .getQualifiedTypeNameInTypeHierarchy(foundMethod |
| .getDeclaringType(), foundParamTypes[i]); |
| } |
| } |
| for (int i = 0; i < methods.length; i++) { |
| if (visitedMethods.get(methods[i]) != null) { |
| continue; |
| } |
| |
| if (!methods[i].getElementName().equals(foundMethodName)) { |
| continue; |
| } |
| if (methods[i].getParameterTypes() == null |
| && foundParamTypes == null) { |
| return methods[i]; |
| } else if (methods[i].getParameterTypes() != null |
| && foundParamTypes != null |
| && foundParamTypes.length == methods[i].getParameterTypes().length) { |
| boolean bSameParams = true; |
| String[] methodParamTypes = methods[i].getParameterTypes(); |
| for (int j = 0; j < foundParamQulifiedTypeNames.length; j++) { |
| String methodParamQualifiedTypeName = JavaClassUtils |
| .getQualifiedTypeNameInTypeHierarchy(methods[i] |
| .getDeclaringType(), methodParamTypes[j]); |
| // if the qualified type name is not same or not subclass or |
| // supper class between each other. |
| if (!methodParamQualifiedTypeName |
| .equals(foundParamQulifiedTypeNames[j]) |
| && !JavaClassUtils.isSubClassOf(methods[i] |
| .getJavaProject(), |
| methodParamQualifiedTypeName, |
| foundParamQulifiedTypeNames[j]) |
| && !JavaClassUtils.isSubClassOf(methods[i] |
| .getJavaProject(), |
| foundParamQulifiedTypeNames[j], |
| methodParamQualifiedTypeName)) { |
| bSameParams = false; |
| break; |
| } |
| } |
| if (bSameParams) { |
| return methods[i]; |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Creates an array of bean properties |
| * |
| * |
| * @param classType |
| * @return it can be <b>null</b>, if property is not found. |
| */ |
| public static JavaBeanProperty[] getBeanProperties(IType classType) { |
| IMethod[] methods; |
| try { |
| methods = JavaClassUtils.getMethods(classType); |
| } catch (JavaModelException e2) { |
| return null; |
| } |
| |
| return getBeanProperties(classType, methods); |
| } |
| |
| /** |
| * Creates an array of bean properties |
| * |
| * @param type |
| * @param methods |
| * |
| * @return - the array of java bean properties. |
| */ |
| public static JavaBeanProperty[] getBeanProperties(IType type, |
| IMethod[] methods) { |
| if (methods == null || methods.length == 0) { |
| return null; |
| } |
| |
| List properties = new ArrayList(); |
| Map visitedMethods = new HashMap(); |
| for (int m = 0; m < methods.length; m++) { |
| String propertyName = null; |
| // if a property's getter method or setter method already visited, |
| // just skip it. |
| if (visitedMethods.get(methods[m]) != null) { |
| continue; |
| } |
| |
| visitedMethods.put(methods[m], methods[m]); |
| |
| // Check getter firstly |
| propertyName = JavaBeanUtils |
| .getPropertyNameFromGetterMethod(methods[m]); |
| |
| if (propertyName != null && propertyName.length() > 0) |
| { |
| String setterMethodName = "set" //$NON-NLS-1$ |
| + JavaBeanUtils.toUpperCaseFirstChar(propertyName); |
| |
| String getterReturnType = null; |
| try { |
| getterReturnType = methods[m].getReturnType(); |
| } catch (JavaModelException e1) { |
| continue; |
| } |
| IMethod setterMethod = getMethodWithSameParamters(methods, |
| visitedMethods, methods[m], setterMethodName, |
| new String[] { getterReturnType }); |
| if (setterMethod != null && setterMethod.exists()) { |
| visitedMethods.put(setterMethod, setterMethod); |
| } |
| |
| properties.add(new JavaBeanProperty(propertyName, |
| getterReturnType, methods[m], setterMethod)); |
| continue; |
| } |
| |
| // Check setter secondly. |
| propertyName = JavaBeanUtils |
| .getPropertyNameFromSetterMethod(methods[m]); |
| |
| if (propertyName != null && propertyName.length() > 0) |
| { |
| // first form of getter method, "get..." |
| String getterMethodName = "get" //$NON-NLS-1$ |
| + JavaBeanUtils.toUpperCaseFirstChar(propertyName); |
| IMethod getterMethod = getMethodWithSameParamters(methods, |
| visitedMethods, methods[m], getterMethodName, null); |
| |
| if (getterMethod != null && getterMethod.exists()) { |
| try { |
| if (getterMethod.getReturnType().equals( |
| methods[m].getParameterTypes()[0])) { |
| visitedMethods.put(getterMethod, getterMethod); |
| } |
| } catch (JavaModelException e) { |
| // need not error logging |
| } |
| } else { |
| // another form of getter method, "is...". |
| getterMethodName = "is" //$NON-NLS-1$ |
| + JavaBeanUtils.toUpperCaseFirstChar(propertyName); |
| getterMethod = getMethodWithSameParamters(methods, |
| visitedMethods, methods[m], getterMethodName, null); |
| try { |
| if (getterMethod != null |
| && getterMethod.exists() |
| && getterMethod.getReturnType().equals( |
| methods[m].getParameterTypes()[0])) { |
| visitedMethods.put(getterMethod, getterMethod); |
| } |
| } catch (JavaModelException e) { |
| // need not error logging |
| } |
| } |
| |
| properties.add(new JavaBeanProperty(propertyName, methods[m] |
| .getParameterTypes()[0], getterMethod, methods[m])); |
| continue; |
| } |
| } |
| |
| JavaBeanProperty[] propertyArray = (JavaBeanProperty[]) properties |
| .toArray(new JavaBeanProperty[properties.size()]); |
| |
| Arrays.sort(propertyArray, new Comparator() { |
| public int compare(Object o1, Object o2) { |
| String name1 = ((JavaBeanProperty) o1).getName(); |
| String name2 = ((JavaBeanProperty) o2).getName(); |
| return name1.compareTo(name2); |
| } |
| }); |
| return propertyArray; |
| } |
| } |