| /******************************************************************************* |
| * Copyright (c) 2006 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| * yyyymmdd bug Email and other contact information |
| * -------- -------- ----------------------------------------------------------- |
| * 20060419 132905 cbrealey@ca.ibm.com - Chris Brealey |
| *******************************************************************************/ |
| package org.eclipse.jst.ws.internal.conformance; |
| |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.jdt.core.Flags; |
| import org.eclipse.jdt.core.IField; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.IMethod; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.ITypeHierarchy; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.Signature; |
| |
| /** |
| * @author cbrealey |
| * A JDTResolver provides several convenience methods for |
| * navigating references between Java classes, methods, |
| * fields and properties. A JDTResolver is constructed |
| * for a Java project whose effective classpath will |
| * govern the scope of search operations performed by the |
| * JDTResolver whenever it needs to convert a signature |
| * into a JDT IType object. |
| */ |
| public class JDTResolver |
| { |
| /** |
| * Creates a new JDTResolver for the given project. |
| * @param project The project providing the context |
| * @param monitor The progress monitor for this resolver |
| * to use, or null if progress monitoring is not desired. |
| * within which this resolver will search for classes. |
| */ |
| public JDTResolver ( IProject project, IProgressMonitor monitor ) |
| { |
| javaProject_ = JavaCore.create(project); |
| monitor_ = monitor; |
| } |
| |
| /** |
| * Returns true if and only if the given JDT IType is an interface. |
| * @param jdtType The type to analyze. |
| * @return True if and only if the given JDT IType is an interface. |
| * @throws JavaModelException If the JDT model fails to |
| * analyze the given type. |
| */ |
| public boolean isInterface ( IType jdtType ) |
| throws JavaModelException |
| { |
| return jdtType.isInterface(); |
| } |
| |
| /** |
| * Returns true if and only if the given JDT IType is an abstract class. |
| * @param jdtType The type to analyze. |
| * @return True if and only if the given JDT IType is an abstract class. |
| * @throws JavaModelException If the JDT model fails to |
| * analyze the given type. |
| */ |
| public boolean isAbstract ( IType jdtType ) |
| throws JavaModelException |
| { |
| return jdtType.isInterface(); |
| //TODO: There's more to it than this. |
| } |
| |
| /** |
| * Returns true if and only if instances of the given JDT IType |
| * can be instantiated via a public default constructor. The class |
| * must have an explicit public default constructor, or have no |
| * explicit constructors at all to meet this criteria. |
| * @param jdtType The type to analyze. |
| * @return True if and only if instances of the type are |
| * public default constructable. |
| * @throws JavaModelException If the JDT model fails to |
| * analyze the given type. |
| */ |
| public boolean isConstructable ( IType jdtType ) |
| throws JavaModelException |
| { |
| IMethod[] methods = jdtType.getMethods(); |
| int numberOfConstructors = 0; |
| for (int m=0; m<methods.length; m++) |
| { |
| if (methods[m].isConstructor()) |
| { |
| numberOfConstructors++; |
| if (methods[m].getNumberOfParameters() == 0 && Flags.isPublic(methods[m].getFlags())) |
| { |
| return true; |
| } |
| } |
| } |
| return numberOfConstructors == 0; |
| } |
| |
| /** |
| * Returns true if and only if the given JDT IType is |
| * a type from the standard JDK, that is, if the given |
| * type belongs under the "java" or "javax" packages. |
| * @param jdtType |
| * @return True if and only if the type is a non-primitive, |
| * Java standard type. |
| * @throws JavaModelException If the JDT model fails to |
| * analyze the given type. |
| */ |
| public boolean isStandardType ( IType jdtType ) |
| throws JavaModelException |
| { |
| String qname = jdtType.getFullyQualifiedName(); |
| return qname.startsWith("java.") || qname.startsWith("javax."); |
| } |
| |
| /** |
| * Returns true if and only if the given JDT IType |
| * is one of the Java primitive types supported by JAX-RPC. |
| * @param jdtType The type to analyze. |
| * @return True if and only if the type is a Java primitive |
| * type supported by JAX-RPC. |
| * @throws JavaModelException If the JDT model fails to |
| * analyze the given type. |
| */ |
| public boolean isPrimitiveType ( IType jdtType ) |
| throws JavaModelException |
| { |
| if (primitiveTypeSet_ == null) |
| { |
| primitiveTypeSet_ = new HashSet(); |
| primitiveTypeSet_.addAll(java.util.Arrays.asList(primitiveTypes_)); |
| } |
| return primitiveTypeSet_.contains(jdtType.getFullyQualifiedName()); |
| } |
| |
| /** |
| * Returns true if and only if the given JDT IType |
| * is one of the Java wrapper types supported by JAX-RPC. |
| * @param jdtType The type to analyze. |
| * @return True if and only if the type is a Java wrapper |
| * type supported by JAX-RPC. |
| * @throws JavaModelException If the JDT model fails to |
| * analyze the given type. |
| */ |
| public boolean isWrapperType ( IType jdtType ) |
| throws JavaModelException |
| { |
| if (wrapperTypeSet_ == null) |
| { |
| wrapperTypeSet_ = new HashSet(); |
| wrapperTypeSet_.addAll(java.util.Arrays.asList(wrapperTypes_)); |
| } |
| return wrapperTypeSet_.contains(jdtType.getFullyQualifiedName()); |
| } |
| |
| /** |
| * Returns true if and only if the given JDT IType |
| * is one of the Java standard types supported by JAX-RPC. |
| * @param jdtType The type to analyze. |
| * @return True if and only if the type is a Java standard |
| * type supported by JAX-RPC. |
| * @throws JavaModelException If the JDT model fails to |
| * analyze the given type. |
| */ |
| public boolean isSupportedType ( IType jdtType ) |
| throws JavaModelException |
| { |
| if (jaxrpcTypeSet_ == null) |
| { |
| jaxrpcTypeSet_ = new HashSet(); |
| jaxrpcTypeSet_.addAll(java.util.Arrays.asList(jaxrpcTypes_)); |
| } |
| return jaxrpcTypeSet_.contains(jdtType.getFullyQualifiedName()); |
| } |
| |
| /** |
| * Returns an array of zero or more JDT IType objects |
| * for the public fields belonging to the given type |
| * @param jdtType The type to analyze. |
| * @param jdtSuperTypes Any supertypes to analyze, |
| * or null to analyze only the <code>jdtType</code>. |
| * @return An array of zero or more public field types. |
| * @throws JavaModelException If the JDT engine fails to |
| * analyze the given types to satisfy this request. |
| */ |
| public IField[] getPublicFields ( IType jdtType, IType[] jdtSuperClasses ) |
| throws JavaModelException |
| { |
| List fieldsList = new LinkedList(); |
| harvestPublicFields(jdtType,fieldsList); |
| if (jdtSuperClasses != null) |
| { |
| for (int t=0; t<jdtSuperClasses.length; t++) |
| { |
| harvestPublicFields(jdtSuperClasses[t],fieldsList); |
| } |
| } |
| return (IField[])fieldsList.toArray(new IField[0]); |
| } |
| |
| /** |
| * Returns an array of zero or more JDT IMethod objects |
| * for the public methods belonging to the given type. |
| * @param jdtType The type to analyze. |
| * @param jdtSuperTypes Any supertypes to analyze, |
| * or null to analyze only the <code>jdtType</code>. |
| * @return An array of zero or more public methods. |
| * @throws JavaModelException If the JDT engine fails to |
| * analyze the given types to satisfy this request. |
| */ |
| public IMethod[] getPublicMethods ( IType jdtType, IType[] jdtSuperClasses ) |
| throws JavaModelException |
| { |
| List methodsList = new LinkedList(); |
| harvestPublicMethods(jdtType,methodsList); |
| if (jdtSuperClasses != null) |
| { |
| for (int t=0; t<jdtSuperClasses.length; t++) |
| { |
| harvestPublicMethods(jdtSuperClasses[t],methodsList); |
| } |
| } |
| return (IMethod[])methodsList.toArray(new IMethod[0]); |
| } |
| |
| /** |
| * Returns an array of zero or more JDT IType objects |
| * for the public properties (getters and/or setters) |
| * belonging to the given type. |
| * @param jdtType The type to analyze. |
| * @param jdtSuperTypes Any supertypes to analyze, |
| * or null to analyze only the <code>jdtType</code>. |
| * @return An array of zero or more public property types. |
| * @throws JavaModelException If the JDT engine fails to |
| * analyze the given types to satisfy this request. |
| */ |
| public IJavaBeanProperty[] getPublicProperties ( IType jdtType, IType[] jdtSuperClasses ) |
| throws JavaModelException |
| { |
| IMethod[] methods = getPublicMethods(jdtType,jdtSuperClasses); |
| Map properties = new HashMap(); |
| for (int m=0; m<methods.length; m++) |
| { |
| String name = getGetterName(methods[m]); |
| if (name != null) |
| { |
| JavaBeanProperty property = (JavaBeanProperty)properties.get(name); |
| if (property == null) |
| { |
| property = new JavaBeanProperty(); |
| property.setName(name); |
| properties.put(name,property); |
| } |
| property.setGetter(methods[m]); |
| } |
| else |
| { |
| name = getSetterName(methods[m]); |
| if (name != null) |
| { |
| JavaBeanProperty property = (JavaBeanProperty)properties.get(name); |
| if (property == null) |
| { |
| property = new JavaBeanProperty(); |
| property.setName(name); |
| properties.put(name,property); |
| } |
| property.setSetter(methods[m]); |
| } |
| } |
| } |
| return (IJavaBeanProperty[])properties.values().toArray(new JavaBeanProperty[0]); |
| } |
| |
| /** |
| * Returns the JDT IType object for the given field. |
| * @param jdtField The field to analyze. |
| * @return The field type. |
| * @throws JavaModelException If the JDT engine fails to |
| * analyze the given field to satisfy this request. |
| */ |
| public IType getFieldType ( IField jdtField ) |
| throws JavaModelException |
| { |
| String signature = jdtField.getTypeSignature(); |
| String typeName = getTypeNameFromSignature(signature); |
| return findType(typeName); |
| } |
| |
| /** |
| * Returns the JDT IType object for the given bean property. |
| * @param javaBeanProperty The bean property to analyze. |
| * @return The property type. |
| * @throws JavaModelException If the JDT engine fails to |
| * analyze the given bean property to satisfy this request. |
| */ |
| public IType getPropertyType ( IJavaBeanProperty javaBeanProperty ) |
| throws JavaModelException |
| { |
| IMethod method = javaBeanProperty.getGetter(); |
| if (method != null) |
| { |
| return getReturnType(method); |
| } |
| else |
| { |
| method = javaBeanProperty.getSetter(); |
| if (method != null) |
| { |
| IType[] parameters = getParameterTypes(method); |
| if (parameters.length > 0) |
| { |
| return parameters[0]; |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the JDT IType object for the return type |
| * of the given method, or null if the method is void. |
| * @param jdtMethod The method to analyze. |
| * @return The method return type, or null if none. |
| * @throws JavaModelException If the JDT engine fails to |
| * analyze the given method to satisfy this request. |
| */ |
| public IType getReturnType ( IMethod jdtMethod ) |
| throws JavaModelException |
| { |
| String signature = jdtMethod.getReturnType(); |
| String typeName = getTypeNameFromSignature(signature); |
| return findType(typeName); |
| } |
| |
| /** |
| * Returns an array of zero or more JDT IType objects |
| * for the parameters of the given method. |
| * @param jdtMethod The method to analyze. |
| * @return An array of zero or more parameter types. |
| * @throws JavaModelException If the JDT engine fails to |
| * analyze the given method to satisfy this request. |
| */ |
| public IType[] getParameterTypes ( IMethod jdtMethod ) |
| throws JavaModelException |
| { |
| String[] signatures = jdtMethod.getParameterTypes(); |
| IType[] types = new IType[signatures.length]; |
| for (int s=0; s<signatures.length; s++) |
| { |
| String typeName = getTypeNameFromSignature(signatures[s]); |
| types[s] = findType(typeName); |
| } |
| return types; |
| } |
| |
| /** |
| * Returns an array of zero or more JDT IType objects |
| * for the exceptions thrown by the given method. |
| * @param jdtMethod The method to analyze. |
| * @return An array of zero or more exception types. |
| * @throws JavaModelException If the JDT engine fails to |
| * analyze the given method to satisfy this request. |
| */ |
| public IType[] getExceptionTypes ( IMethod jdtMethod ) |
| throws JavaModelException |
| { |
| String[] signatures = jdtMethod.getExceptionTypes(); |
| IType[] types = new IType[signatures.length]; |
| for (int s=0; s<signatures.length; s++) |
| { |
| String typeName = getTypeNameFromSignature(signatures[s]); |
| types[s] = findType(typeName); |
| } |
| return types; |
| } |
| |
| /** |
| * Returns an array of zero or more types representing |
| * the superclasses, if any, of the given IType. |
| * @param jdtType The type to analyze. |
| * @param jdtSuperTypes Any supertypes to analyze, |
| * or null to analyze only the <code>jdtType</code>. |
| * @return An array of zero or more superclass types. |
| * @throws JavaModelException If the JDT engine fails to |
| * analyze the given type to satisfy this request. |
| */ |
| public IType[] getSuperClasses ( IType jdtType ) |
| throws JavaModelException |
| { |
| ITypeHierarchy hierarchy = jdtType.newSupertypeHierarchy(monitor_); |
| IType[] superClasses = hierarchy.getAllSuperclasses(jdtType); |
| int n = superClasses.length - 1; |
| if (n >= 0 && superClasses[n].getFullyQualifiedName().equals("java.lang.Object")) |
| { |
| IType[] superClassesExcludingObject = new IType[n]; |
| for (int i=0; i<n; i++) |
| { |
| superClassesExcludingObject[i] = superClasses[i]; |
| } |
| return superClassesExcludingObject; |
| } |
| return superClasses; |
| } |
| |
| /** |
| * Extracts the qualified type name from a JDT signature. |
| * @param signature The signature to examine. |
| * @return The qualified type name from the signature. |
| */ |
| public String getTypeNameFromSignature ( String signature ) |
| { |
| String packageName = Signature.getSignatureQualifier(signature); |
| String baseName = Signature.getSignatureSimpleName(signature); |
| String typeName = (packageName.trim().equals("")?"":packageName+".") + baseName; |
| return typeName; |
| } |
| |
| /** |
| * Attempts to find a JDT IType object for the given |
| * fully qualified type name. |
| * @param typeName The qualified name of the type to find. |
| * @return The IType object of the given qualified name, |
| * or null if no type could be found in the workspace. |
| */ |
| public IType findType ( String typeName ) |
| throws JavaModelException |
| { |
| IType type = javaProject_.findType(typeName); |
| return type; |
| /* |
| SearchEngine engine = new SearchEngine(); |
| IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] {javaProject_}); |
| SearchPattern pattern = SearchPattern.createPattern( |
| "*"+typeName, |
| IJavaSearchConstants.CLASS_AND_INTERFACE, |
| IJavaSearchConstants.DECLARATIONS, |
| SearchPattern.R_PATTERN_MATCH |
| ); |
| SearchParticipant[] participants = new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()}; |
| final IType[] type = new IType[1]; |
| SearchRequestor requestor = new SearchRequestor() |
| { |
| public void acceptSearchMatch ( SearchMatch match ) |
| { |
| Object element = match.getElement(); |
| System.out.println("Matched element "+element==null?"null":element.toString()); |
| if (element != null && element instanceof IType) |
| { |
| type[0] = (IType)element; |
| } |
| } |
| }; |
| try |
| { |
| engine.search(pattern,participants,scope,requestor,monitor_); |
| } |
| catch (CoreException e) |
| { |
| throw new JavaModelException(e); |
| } |
| return type[0]; |
| */ |
| } |
| |
| /** |
| * Finds all public, non-constructor IMethods belonging |
| * to the given IType and adds them to the given list. |
| * @param jdtType The type whose methods are to be harvested. |
| * @param list The list to which the harvested methods will be added. |
| * @throws JavaModelException If the JDT engine fails to |
| * analyze the given type to satisfy this request. |
| */ |
| public void harvestPublicMethods ( IType jdtType, List list ) |
| throws JavaModelException |
| { |
| IMethod[] methods = jdtType.getMethods(); |
| for (int m=0; m<methods.length; m++) |
| { |
| if (!methods[m].isConstructor() && Flags.isPublic(methods[m].getFlags())) |
| { |
| list.add(methods[m]); |
| } |
| } |
| } |
| |
| /** |
| * Finds all public IFields belonging |
| * to the given IType and adds them to the given list. |
| * @param jdtType The type whose fields are to be harvested. |
| * @param list The list to which the harvested fields will be added. |
| * @throws JavaModelException If the JDT engine fails to |
| * analyze the given type to satisfy this request. |
| */ |
| public void harvestPublicFields ( IType jdtType, List list ) |
| throws JavaModelException |
| { |
| IField[] fields = jdtType.getFields(); |
| for (int f=0; f<fields.length; f++) |
| { |
| if (Flags.isPublic(fields[f].getFlags())) |
| { |
| list.add(fields[f]); |
| } |
| } |
| } |
| |
| /** |
| * If the given method is a getter according to the Bean spec |
| * (eg. "MyType getMyProperty ()" or "boolean isMyProperty ()") |
| * return the corresponding bean property name (eg. "myProperty"), |
| * otherwise, return null. |
| * @param method The method to check. |
| * @return The property name or none if the method is not a getter. |
| */ |
| public String getGetterName ( IMethod method ) |
| { |
| String methodName = method.getElementName(); |
| if (methodName.startsWith("get") && methodName.length() > 3) |
| { |
| //TODO Check signature. Must be "T getP()" or "T[] getP()" or "T getP(int)". |
| return methodName.substring(3,4).toLowerCase() + methodName.substring(4); |
| } |
| else if (methodName.startsWith("is") && methodName.length() > 3) |
| { |
| //TODO Check signature. Must be "boolean isP()". |
| return methodName.substring(2,3).toLowerCase() + methodName.substring(3); |
| } |
| return null; |
| } |
| |
| /** |
| * If the given method is a setter according to the Bean spec |
| * (eg. "void setMyProperty (MyType)" return the corresponding |
| * bean property name (eg. "myProperty"), otherwise, return null. |
| * @param method The method to check. |
| * @return The property name or none if the method is not a setter. |
| */ |
| public String getSetterName ( IMethod method ) |
| { |
| String methodName = method.getElementName(); |
| if (methodName.startsWith("set") && methodName.length() > 3) |
| { |
| //TODO Check signature. Must be "T getP()" or "T[] getP()" or "T getP(int)". |
| return methodName.substring(3,4).toLowerCase() + methodName.substring(4); |
| } |
| return null; |
| } |
| |
| /* |
| * The Java project that governs the search scope for this resolver. |
| */ |
| private IJavaProject javaProject_; |
| |
| /* |
| * The progress monitor to use, if any. |
| */ |
| private IProgressMonitor monitor_; |
| |
| /* |
| * The set of Java wrapper types. |
| */ |
| private static HashSet wrapperTypeSet_ = null; |
| private static String[] wrapperTypes_ = { |
| "java.lang.Character", |
| "java.lang.Boolean", |
| "java.lang.Byte", |
| "java.lang.Short", |
| "java.lang.Integer", |
| "java.lang.Long", |
| "java.lang.Float", |
| "java.lang.Double" |
| }; |
| |
| /* |
| * The set of Java primitive types. |
| */ |
| private static HashSet primitiveTypeSet_ = null; |
| private static String[] primitiveTypes_ = { |
| "char", |
| "boolean", |
| "byte", |
| "short", |
| "int", |
| "long", |
| "float", |
| "double" |
| }; |
| |
| /* |
| * The set of JAX-RPC supported Java standard types. |
| */ |
| private static HashSet jaxrpcTypeSet_ = null; |
| private static String[] jaxrpcTypes_ = { |
| "boolean", |
| "byte", |
| "short", |
| "int", |
| "long", |
| "float", |
| "double", |
| "java.lang.Boolean", |
| "java.lang.Byte", |
| "java.lang.Short", |
| "java.lang.Integer", |
| "java.lang.Long", |
| "java.lang.Float", |
| "java.lang.Double", |
| "java.lang.String", |
| "java.util.Date", |
| "java.util.Calendar", |
| "java.math.BigInteger", |
| "java.math.BigDecimal", |
| "java.net.URI", |
| "javax.xml.namespace.QName" |
| }; |
| } |