/******************************************************************************* * Copyright (c) 2007, 2015 Spring IDE Developers * 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: * Spring IDE Developers - initial API and implementation *******************************************************************************/ package org.springframework.ide.eclipse.core.java; import java.io.FileNotFoundException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IImportDeclaration; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaModel; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.ITypeParameter; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.search.IJavaSearchConstants; import org.eclipse.jdt.core.search.IJavaSearchScope; import org.eclipse.jdt.core.search.SearchEngine; import org.eclipse.jdt.core.search.SearchMatch; import org.eclipse.jdt.core.search.SearchParticipant; import org.eclipse.jdt.core.search.SearchPattern; import org.eclipse.jdt.core.search.SearchRequestor; import org.eclipse.jdt.launching.JavaRuntime; import org.osgi.framework.Bundle; import org.springframework.ide.eclipse.core.SpringCore; import org.springframework.ide.eclipse.core.java.Introspector.Public; import org.springframework.ide.eclipse.core.java.Introspector.Static; import org.springframework.ide.eclipse.core.java.typehierarchy.TypeHierarchyEngine; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springsource.ide.eclipse.commons.core.SpringCoreUtils; import org.springsource.ide.eclipse.commons.core.StatusHandler; /** * Utility class that provides several helper methods for working with Eclipse's JDT. * @author Christian Dupuis * @author Martin Lippert * @author Leo Dos Santos * @since 2.0 */ public class JdtUtils { public static final String CLASS_FILE_EXTENSION = ".class"; public static final String GROOVY_FILE_EXTENSION = ".groovy"; public static final String JAVA_FILE_EXTENSION = ".java"; private static final String AJDT_CLASS = "org.eclipse.ajdt.core.javaelements.AJCompilationUnitManager"; private static final String AJDT_NATURE = "org.eclipse.ajdt.ui.ajnature"; private static final String CLASSPATH_FILENAME = ".classpath"; private static final boolean IS_AJDT_PRESENT = isAjdtPresent(); /** * Creates specified Java project. */ public static IJavaProject createJavaProject(String projectName, IProgressMonitor monitor) throws CoreException { IProject project = SpringCoreUtils.createProject(projectName, null, monitor); if (monitor.isCanceled()) { throw new OperationCanceledException(); } if (!project.hasNature(JavaCore.NATURE_ID)) { SpringCoreUtils.addProjectNature(project, JavaCore.NATURE_ID, monitor); } IJavaProject jproject = JavaCore.create(project); // append JRE entry jproject.setRawClasspath(new IClasspathEntry[] { getJreVariableEntry() }, monitor); jproject.setOutputLocation(project.getFullPath(), monitor); if (monitor.isCanceled()) { throw new OperationCanceledException(); } return jproject; } /** * Checks if the given <code>type</code> implements/extends <code>className</code>. */ public static boolean doesImplement(IResource resource, IType type, String className) { return doesImplement(resource, type, className, SpringCore.getTypeHierarchyEngine()); } /** * Checks if the given <code>type</code> implements/extends <code>className</code>. */ public static boolean doesImplement(IResource resource, IType type, String className, TypeHierarchyEngine typeEngine) { if (resource == null || type == null || className == null) { return false; } if (className.startsWith("java.") || className.startsWith("javax.")) { try { ClassLoader cls = getClassLoader(resource.getProject(), null); Class<?> typeClass = cls.loadClass(type.getFullyQualifiedName('$')); Class<?> interfaceClass = cls.loadClass(className); return typeClass.equals(interfaceClass) || interfaceClass.isAssignableFrom(typeClass); } catch (Throwable e) { // ignore this and fall back to JDT does implement checks } } if (System.getProperty(TypeHierarchyEngine.ENABLE_PROPERTY, "true").equals("true")) { return typeEngine.doesImplement(type, className) || typeEngine.doesExtend(type, className); } else { return doesImplementWithJdt(resource, type, className); } } public static IType getAjdtType(IProject project, String className) { IJavaProject javaProject = getJavaProject(project); if (IS_AJDT_PRESENT && javaProject != null && className != null) { try { IType type = null; // First look for the type in the project if (isAjdtProject(project)) { type = AjdtUtils.getAjdtType(project, className); if (type != null) { return type; } } // Then look for the type in the referenced Java projects for (IProject refProject : project.getReferencedProjects()) { if (isAjdtProject(refProject)) { type = AjdtUtils.getAjdtType(refProject, className); if (type != null) { return type; } } } } catch (CoreException e) { SpringCore.log("Error getting Java type '" + className + "'", e); } } return null; } public static List<IJavaProject> getAllDependingJavaProjects(IJavaProject project) { List<IJavaProject> javaProjects = new ArrayList<IJavaProject>(); IJavaModel model = JavaCore.create(ResourcesPlugin.getWorkspace().getRoot()); if (model != null) { try { String[] names = project.getRequiredProjectNames(); IJavaProject[] projects = model.getJavaProjects(); for (int index = 0; index < projects.length; index++) { for (int offset = 0; offset < names.length; offset++) { String name = projects[index].getProject().getName(); if (name.equals(names[offset])) { javaProjects.add(projects[index]); } } } } catch (JavaModelException exception) { } } return javaProjects; } /** * Creates a Set of {@link URL}s from the OSGi bundle class path manifest entry. */ public static Set<URL> getBundleClassPath(String bundleId) { Set<URL> paths = new HashSet<URL>(); try { Bundle bundle = Platform.getBundle(bundleId); if (bundle != null) { String bundleClassPath = (String) bundle.getHeaders() .get(org.osgi.framework.Constants.BUNDLE_CLASSPATH); if (bundleClassPath != null) { String[] classPathEntries = StringUtils.delimitedListToStringArray(bundleClassPath, ","); for (String classPathEntry : classPathEntries) { if (".".equals(classPathEntry.trim())) { paths.add(FileLocator.toFileURL(bundle.getEntry("/"))); } else { try { paths.add(FileLocator.toFileURL(new URL(bundle.getEntry("/"), "/" + classPathEntry.trim()))); } catch (FileNotFoundException e) { SpringCore.log("bundle classpath entry \"" + classPathEntry.trim() + "\" of bundle " + bundle.getSymbolicName() + " not found and therefore ignored", e); } } } } else { paths.add(FileLocator.toFileURL(bundle.getEntry("/"))); } } } catch (MalformedURLException e) { SpringCore.log(e); } catch (IOException e) { SpringCore.log(e); } return paths; } /** * @since 2.6.0 */ public static IJavaElement getByHandle(String handle) { if (IS_AJDT_PRESENT) { return AjdtUtils.getByHandle(handle); } else { return JavaCore.create(handle); } } /** * Create a {@link ClassLoader} from the class path configuration of the given <code>project</code>. * @param project the {@link IProject} * @param useParentClassLoader true if the current OSGi class loader should be used as parent class loader for the * constructed class loader. * @return {@link ClassLoader} instance constructed from the <code>project</code>'s build path configuration */ public static ClassLoader getClassLoader(IProject project, ClassLoader parentClassLoader) { return ProjectClassLoaderCache.getClassLoader(project, parentClassLoader); } public static void removeClassLoaderEntryFromCache(IProject project) { ProjectClassLoaderCache.removeClassLoaderEntryFromCache(project); } public static IMethod getConstructor(IType type, Class[] parameterTypes) { String[] parameterTypesAsString = getParameterTypesAsStringArray(parameterTypes); return getConstructor(type, parameterTypesAsString); } public static IMethod getConstructor(IType type, String[] parameterTypes) { try { Set<IMethod> methods = Introspector.getAllConstructors(type); for (IMethod method : methods) { if (method.getParameterTypes().length == parameterTypes.length) { String[] methodParameterTypes = getParameterTypesAsStringArray(method); if (Arrays.deepEquals(parameterTypes, methodParameterTypes)) { return method; } } } } catch (JavaModelException e) { } return null; } public static IField getField(IType type, String fieldName) { return getField(type, fieldName, true); } /** * @since 3.2.0 */ public static IField getField(IType type, String fieldName, boolean includeHierarchy) { try { while (type != null) { for (IField field : type.getFields()) { if (field.getElementName().equals(fieldName)) { return field; } } if (!includeHierarchy) break; type = Introspector.getSuperType(type); } } catch (JavaModelException e) { } return null; } /** * Returns a flat list of all interfaces and super types for the given {@link IType}. */ public static List<String> getFlatListOfClassAndInterfaceNames(IType parameterType, IType type) { List<String> requiredTypes = new ArrayList<String>(); if (parameterType != null) { do { try { requiredTypes.add(parameterType.getFullyQualifiedName()); String[] interfaceNames = parameterType.getSuperInterfaceNames(); for (String interfaceName : interfaceNames) { if (interfaceName != null) { if (type.isBinary()) { requiredTypes.add(interfaceName); } String resolvedName = resolveClassName(interfaceName, type); if (resolvedName != null) { requiredTypes.add(resolvedName); } } } parameterType = Introspector.getSuperType(parameterType); } catch (JavaModelException e) { } } while (parameterType != null && !parameterType.getFullyQualifiedName().equals(Object.class.getName())); } return requiredTypes; } /** * Returns the corresponding Java project or <code>null</code> a for given project. * @param project the project the Java project is requested for * @return the requested Java project or <code>null</code> if the Java project is not defined or the project is not * accessible */ public static IJavaProject getJavaProject(IProject project) { if (project.isAccessible()) { try { if (project.hasNature(JavaCore.NATURE_ID)) { return (IJavaProject) project.getNature(JavaCore.NATURE_ID); } } catch (CoreException e) { SpringCore.log("Error getting Java project for project '" + project.getName() + "'", e); } } return null; } public static IJavaProject getJavaProject(IResource config) { IJavaProject project = JavaCore.create(config.getProject()); return project; } /** * Returns the corresponding Java type for given full-qualified class name. * @param project the JDT project the class belongs to * @param className the full qualified class name of the requested Java type * @return the requested Java type or null if the class is not defined or the project is not accessible */ public static IType getJavaType(IProject project, String className) { IJavaProject javaProject = JdtUtils.getJavaProject(project); if (className != null) { // For inner classes replace '$' by '.' String unchangedClassName = null; int pos = className.lastIndexOf('$'); if (pos > 0) { unchangedClassName = className; className = className.replace('$', '.'); } try { IType type = null; // First look for the type in the Java project if (javaProject != null) { type = javaProject.findType(className, new NullProgressMonitor()); if (type == null && unchangedClassName != null) { type = findTypeWithInnerClassesInvolved(javaProject, unchangedClassName, new NullProgressMonitor()); } if (type != null) { return type; } } // Then look for the type in the referenced Java projects for (IProject refProject : project.getReferencedProjects()) { IJavaProject refJavaProject = JdtUtils.getJavaProject(refProject); if (refJavaProject != null) { type = refJavaProject.findType(className); if (type == null && unchangedClassName != null) { type = findTypeWithInnerClassesInvolved(javaProject, unchangedClassName, new NullProgressMonitor()); } if (type != null) { return type; } } } // fall back and try to locate the class using AJDT return getAjdtType(project, className); } catch (CoreException e) { SpringCore.log("Error getting Java type '" + className + "'", e); } } return null; } protected static IType findTypeWithInnerClassesInvolved(IJavaProject javaProject, String fullClassName, NullProgressMonitor progressMonitor) throws JavaModelException { IType result = javaProject.findType(fullClassName, progressMonitor); /* if (result == null || !result.exists()) { String mainClassName = fullClassName.substring(0, fullClassName.indexOf('$')); IType mainClass = javaProject.findType(mainClassName, progressMonitor); if (mainClass != null && mainClass.exists() && !mainClass.isBinary()) { IType outerClass = mainClass; String innerClasses = fullClassName.substring(fullClassName.indexOf('$') + 1); StringTokenizer innerClassTokens = new StringTokenizer(innerClasses, "$"); while (innerClassTokens.hasMoreTokens()) { String innerClass = innerClassTokens.nextToken(); try { int anonymousInnerClassNo = Integer.parseInt(innerClass); outerClass = outerClass.getType("", anonymousInnerClassNo); } catch (NumberFormatException e) { outerClass = outerClass.getType(innerClass); } }; result = outerClass; } } */ return result; } public static final IType getJavaTypeForMethodReturnType(IMethod method, IType contextType) { try { return JdtUtils.getJavaTypeFromSignatureClassName(method.getReturnType(), contextType); } catch (JavaModelException e) { } return null; } public static IType getJavaTypeFromSignatureClassName(String className, IType contextType) { if (contextType == null || className == null) { return null; } try { return JdtUtils.getJavaType(contextType.getJavaProject().getProject(), JdtUtils .resolveClassNameBySignature(className, contextType)); } catch (IllegalArgumentException e) { // do Nothing } return null; } public static final List<IType> getJavaTypesForMethodParameterTypes(IMethod method, IType contextType) { if (method == null || method.getParameterTypes() == null || method.getParameterTypes().length == 0) { return Collections.EMPTY_LIST; } List<IType> parameterTypes = new ArrayList<IType>(method.getParameterTypes().length); String[] parameterTypeNames = method.getParameterTypes(); for (String parameterTypeName : parameterTypeNames) { parameterTypes.add(JdtUtils.getJavaTypeFromSignatureClassName(parameterTypeName, contextType)); } return parameterTypes; } public static IClasspathEntry getJreVariableEntry() { return JavaRuntime.getDefaultJREContainerEntry(); } public static int getLineNumber(IJavaElement element) { if (element != null && element instanceof IMethod) { try { IMethod method = (IMethod) element; int lines = 0; if (method.getDeclaringType() != null && method.getDeclaringType().getCompilationUnit() != null) { String targetsource = method.getDeclaringType().getCompilationUnit().getSource(); if (targetsource != null) { String sourceuptomethod = targetsource.substring(0, method.getNameRange().getOffset()); char[] chars = new char[sourceuptomethod.length()]; sourceuptomethod.getChars(0, sourceuptomethod.length(), chars, 0); for (char element0 : chars) { if (element0 == '\n') { lines++; } } return new Integer(lines + 1); } } } catch (JavaModelException e) { } } else if (element != null && element instanceof IType && ((IType) element).getCompilationUnit() != null) { try { IType type = (IType) element; int lines = 0; String targetsource = type.getCompilationUnit().getSource(); if (targetsource != null) { String sourceuptomethod = targetsource.substring(0, type.getNameRange().getOffset()); char[] chars = new char[sourceuptomethod.length()]; sourceuptomethod.getChars(0, sourceuptomethod.length(), chars, 0); for (char element0 : chars) { if (element0 == '\n') { lines++; } } return new Integer(lines + 1); } } catch (JavaModelException e) { } } else if (element != null && element instanceof IField) { try { IField type = (IField) element; int lines = 0; ICompilationUnit cu = type.getCompilationUnit(); if (cu != null) { String targetsource = cu.getSource(); if (targetsource != null) { String sourceuptomethod = targetsource.substring(0, type.getNameRange().getOffset()); char[] chars = new char[sourceuptomethod.length()]; sourceuptomethod.getChars(0, sourceuptomethod.length(), chars, 0); for (char element0 : chars) { if (element0 == '\n') { lines++; } } return new Integer(lines + 1); } } } catch (JavaModelException e) { } } return new Integer(-1); } public static IMethod getMethod(IType type, String methodName, Class[] parameterTypes) { String[] parameterTypesAsString = getParameterTypesAsStringArray(parameterTypes); return getMethod(type, methodName, parameterTypesAsString); } public static IMethod getMethod(IType type, String methodName, String[] parameterTypes) { return getMethod(type, methodName, parameterTypes, true); } /** * @since 3.2.0 */ public static IMethod getMethod(IType type, String methodName, String[] parameterTypes, boolean includeHierarchy) { int index = methodName.indexOf('('); if (index >= 0) { methodName = methodName.substring(0, index); } try { while (type != null) { for (IMethod method : Introspector.getMethods(type)) { if (method.getElementName().equals(methodName) && method.getParameterTypes().length == parameterTypes.length) { String[] methodParameterTypes = getParameterTypesAsStringArray(method); if (Arrays.deepEquals(parameterTypes, methodParameterTypes)) { return method; } } } if (!includeHierarchy) break; type = Introspector.getSuperType(type); } return Introspector.findMethod(type, methodName, parameterTypes.length, Public.YES, Static.DONT_CARE); } catch (JavaModelException e) { } return null; } public static String getMethodName(IMethod method) { // Special support Ajdt intertype declarations String methodName = method.getElementName(); int index = methodName.lastIndexOf('.'); if (index > 0) { methodName = methodName.substring(index + 1); } return methodName; } public static String[] getParameterTypesString(IMethod method) { try { String[] parameterQualifiedTypes = Signature.getParameterTypes(method.getSignature()); int length = parameterQualifiedTypes == null ? 0 : parameterQualifiedTypes.length; String[] parameterPackages = new String[length]; for (int i = 0; i < length; i++) { parameterQualifiedTypes[i] = parameterQualifiedTypes[i].replace('/', '.'); parameterPackages[i] = Signature.getSignatureSimpleName(parameterQualifiedTypes[i]); } return parameterPackages; } catch (IllegalArgumentException e) { } catch (JavaModelException e) { } return null; } public static String getParentName(IMethod method) { // Special support Ajdt intertype declarations String methodName = method.getElementName(); int index = methodName.lastIndexOf('.'); if (index > 0) { return methodName.substring(0, index); } else { return method.getParent().getElementName(); } } public static IProjectClassLoaderSupport getProjectClassLoaderSupport(IProject je, ClassLoader parentClassLoader) { return new DefaultProjectClassLoaderSupport(je, parentClassLoader); } public static String getPropertyNameFromMethodName(IMethod method) { // Special support Ajdt intertype declarations String methodName = method.getElementName(); int index = methodName.lastIndexOf('.'); if (index > 0) { methodName = methodName.substring(index + 1); } String replaceText = methodName.substring("set".length()); if (replaceText != null) { replaceText = java.beans.Introspector.decapitalize(replaceText); } return replaceText; } public static String getReturnTypeString(IMethod method, boolean classTypesOnly) { try { String qualifiedReturnType = Signature.getReturnType(method.getSignature()); if (!classTypesOnly || qualifiedReturnType.startsWith("L") || qualifiedReturnType.startsWith("Q")) { return Signature.getSignatureSimpleName(qualifiedReturnType.replace('/', '.')); } } catch (IllegalArgumentException e) { } catch (JavaModelException e) { } return null; } public static IResource getSourceResource(IResource classFile) { try { if (isJavaProject(classFile) && classFile.getName().endsWith(CLASS_FILE_EXTENSION)) { IPath classFilePath = classFile.getFullPath(); String classFileName = null; IJavaProject project = getJavaProject(classFile); IPath defaultOutput = project.getOutputLocation(); if (defaultOutput.isPrefixOf(classFilePath)) { classFileName = classFilePath.removeFirstSegments(defaultOutput.segmentCount()).toString(); } else { for (IClasspathEntry entry : project.getRawClasspath()) { if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { IPath output = entry.getOutputLocation(); if (output != null) { if (classFilePath.isPrefixOf(output)) { classFileName = classFilePath.removeFirstSegments(output.segmentCount()).toString(); } } } } } if (classFileName != null) { // Replace file extension String sourceFileName = classFileName.replace(".class", ".java"); for (IClasspathEntry entry : project.getRawClasspath()) { if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { IPath path = entry.getPath().append(sourceFileName).removeFirstSegments(1); IResource resource = project.getProject().findMember(path); if (resource != null) { return resource; } } } } } } catch (JavaModelException e) { } return null; } public static boolean isAjdtPresent() { return Platform.getBundle("org.eclipse.ajdt.core") != null; } /** * Returns true if given resource's project is a ADJT project. */ public static boolean isAjdtProject(IResource resource) { if (resource != null && resource.isAccessible()) { IProject project = resource.getProject(); if (project != null) { try { return project.hasNature(AJDT_NATURE); } catch (CoreException e) { SpringCore.log(e); } } } return false; } /** * Determines if the <code>resource</code> under question is the .classpath file of a {@link IJavaProject}. */ public static boolean isClassPathFile(IResource resource) { String classPathFileName = resource.getProject().getFullPath().append(CLASSPATH_FILENAME).toString(); return resource.getFullPath().toString().equals(classPathFileName); } /** * Returns true if given resource's project is a Java project. */ public static boolean isJavaProject(IResource resource) { if (resource != null && resource.isAccessible()) { IProject project = resource.getProject(); if (project != null) { try { return project.hasNature(JavaCore.NATURE_ID); } catch (CoreException e) { SpringCore.log(e); } } } return false; } public static boolean isTypeAjdtElement(IType type) { if (IS_AJDT_PRESENT) { return AjdtUtils.isTypeAjdtElement(type); } return false; } public static boolean isTypeGroovyElement(IType type) { // TODO CD verify following check with Groovy Eclipse ICompilationUnit cu = type.getCompilationUnit(); if (cu != null && cu.getResource() != null) { return cu.getResource().getName().endsWith(GROOVY_FILE_EXTENSION); } else if (cu != null) { try { IResource resource = cu.getUnderlyingResource(); if (resource != null) { return resource.getName().endsWith(GROOVY_FILE_EXTENSION); } } catch (JavaModelException e) { // ignore } } return false; } public static String resolveClassName(String className, IType type) { if (className == null || type == null) { return className; } // replace binary $ inner class name syntax with . for source level className = className.replace('$', '.'); String dotClassName = new StringBuilder().append('.').append(className).toString(); IProject project = type.getJavaProject().getProject(); try { // Special handling for some well-know classes if (className.startsWith("java.lang") && getJavaType(project, className) != null) { return className; } // Check if the class is imported if (!type.isBinary()) { // Strip className to first segment to support ReflectionUtils.MethodCallback int ix = className.lastIndexOf('.'); String firstClassNameSegment = className; if (ix > 0) { firstClassNameSegment = className.substring(0, ix); } // Iterate the imports for (IImportDeclaration importDeclaration : type.getCompilationUnit().getImports()) { String importName = importDeclaration.getElementName(); // Wildcard imports -> check if the package + className is a valid type if (importDeclaration.isOnDemand()) { String newClassName = new StringBuilder(importName.substring(0, importName.length() - 1)) .append(className).toString(); if (getJavaType(project, newClassName) != null) { return newClassName; } } // Concrete import matching .className at the end -> check if type exists else if (importName.endsWith(dotClassName) && getJavaType(project, importName) != null) { return importName; } // Check if className is multi segmented (ReflectionUtils.MethodCallback) // -> check if the first segment else if (!className.equals(firstClassNameSegment)) { if (importName.endsWith(firstClassNameSegment)) { String newClassName = new StringBuilder(importName.substring(0, importName.lastIndexOf('.') + 1)).append(className).toString(); if (getJavaType(project, newClassName) != null) { return newClassName; } } } } } // Check if the class is in the same package as the type String packageName = type.getPackageFragment().getElementName(); String newClassName = new StringBuilder(packageName).append(dotClassName).toString(); if (getJavaType(project, newClassName) != null) { return newClassName; } // Check if the className is sufficient (already fully-qualified) if (getJavaType(project, className) != null) { return className; } // Check if the class is coming from the java.lang newClassName = new StringBuilder("java.lang").append(dotClassName).toString(); if (getJavaType(project, newClassName) != null) { return newClassName; } // Fall back to full blown resolution String[][] fullInter = type.resolveType(className); if (fullInter != null && fullInter.length > 0) { return fullInter[0][0] + "." + fullInter[0][1]; } } catch (JavaModelException e) { SpringCore.log(e); } return className; } public static String resolveClassNameBySignature(String className, IType type) { // in case the type is already resolved if (className != null && className.length() > 0 && className.charAt(0) == Signature.C_RESOLVED) { return Signature.toString(className).replace('$', '.'); } // otherwise do the resolving else { className = Signature.toString(className).replace('$', '.'); return resolveClassName(className, type); } } public static void visitTypeAst(IType type, ASTVisitor visitor) { if (type != null && type.getCompilationUnit() != null) { ASTParser parser = ASTParser.newParser(AST.JLS3); parser.setSource(type.getCompilationUnit()); parser.setResolveBindings(true); ASTNode node = parser.createAST(new NullProgressMonitor()); node.accept(visitor); } } private static boolean doesImplementWithJdt(IResource resource, IType type, String className) { IType interfaceType = getJavaType(resource.getProject(), className); if (type != null && interfaceType != null) { try { IType[] subTypes = SuperTypeHierarchyCache.getTypeHierarchy(interfaceType) .getAllSubtypes(interfaceType); if (subTypes != null) { for (IType subType : subTypes) { if (subType.equals(type)) { return true; } } } } catch (JavaModelException ex) { SpringCore.log(ex); } } return false; } private static String[] getParameterTypesAsStringArray(Class[] parameterTypes) { String[] parameterTypesAsString = new String[parameterTypes.length]; for (int i = 0; i < parameterTypes.length; i++) { parameterTypesAsString[i] = ClassUtils.getQualifiedName(parameterTypes[i]); } return parameterTypesAsString; } private static String[] getParameterTypesAsStringArray(IMethod method) { Set<String> typeParameterNames = new HashSet<String>(); try { for (ITypeParameter param : method.getDeclaringType().getTypeParameters()) { typeParameterNames.add(param.getElementName()); } for (ITypeParameter param : method.getTypeParameters()) { typeParameterNames.add(param.getElementName()); } } catch (JavaModelException e) { } String[] parameterTypesAsString = new String[method.getParameterTypes().length]; for (int i = 0; i < method.getParameterTypes().length; i++) { String parameterTypeString = Signature.getElementType(method.getParameterTypes()[i]); boolean isArray = !parameterTypeString.equals(method.getParameterTypes()[i]); String parameterType = resolveClassNameBySignature(parameterTypeString, method.getDeclaringType()); if (typeParameterNames.contains(parameterType)) { parameterTypesAsString[i] = Object.class.getName() + (isArray ? ClassUtils.ARRAY_SUFFIX : ""); } else { parameterTypesAsString[i] = parameterType + (isArray ? ClassUtils.ARRAY_SUFFIX : ""); } } return parameterTypesAsString; } static class DefaultProjectClassLoaderSupport implements IProjectClassLoaderSupport { private ClassLoader classLoader; private ClassLoader weavingClassLoader; public DefaultProjectClassLoaderSupport(IProject javaProject, ClassLoader parentClassLoader) { setupClassLoaders(javaProject, parentClassLoader); } public void executeCallback(IProjectClassLoaderAwareCallback callback) throws Throwable { try { activateWeavingClassLoader(); callback.doWithActiveProjectClassLoader(); } finally { recoverClassLoader(); } } public ClassLoader getProjectClassLoader() { return this.weavingClassLoader; } /** * Activates the weaving class loader as thread context classloader. * <p> * Use {@link #recoverClassLoader()} to recover the original thread context classloader */ private void activateWeavingClassLoader() { Thread.currentThread().setContextClassLoader(weavingClassLoader); } private void recoverClassLoader() { Thread.currentThread().setContextClassLoader(classLoader); } private void setupClassLoaders(IProject project, ClassLoader parentClassLoader) { classLoader = Thread.currentThread().getContextClassLoader(); weavingClassLoader = ProjectClassLoaderCache.getClassLoader(project, parentClassLoader); } } public static Set<IType> searchForJavaConfigs(SearchPattern pattern, IJavaSearchScope scope) { final Set<IType> annotatedTypes = new HashSet<IType>(); SearchRequestor requestor = new SearchRequestor() { @Override public void acceptSearchMatch(SearchMatch match) throws CoreException { if (match.getAccuracy() == SearchMatch.A_ACCURATE && !match.isInsideDocComment()) { Object element = match.getElement(); if (element instanceof IType) { annotatedTypes.add((IType) element); } else if (element instanceof IMethod) { IType type = ((IMethod) element).getDeclaringType(); if (type != null) { annotatedTypes.add(type); } } } } }; try { new SearchEngine().search(pattern, new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() }, scope, requestor, null); } catch (CoreException e) { StatusHandler.log(new Status(IStatus.ERROR, SpringCore.PLUGIN_ID, "An error occurred while searching for Java config files.", e)); } return annotatedTypes; } public static Set<IType> searchForJavaConfigs(IJavaSearchScope scope) { SearchPattern configurationPattern = SearchPattern.createPattern("org.springframework.context.annotation.Configuration", IJavaSearchConstants.ANNOTATION_TYPE, IJavaSearchConstants.ANNOTATION_TYPE_REFERENCE, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE); SearchPattern componentPattern = SearchPattern.createPattern( "org.springframework.stereotype.Component", IJavaSearchConstants.ANNOTATION_TYPE, IJavaSearchConstants.ANNOTATION_TYPE_REFERENCE, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE); SearchPattern beanPattern = SearchPattern.createPattern("org.springframework.context.annotation.Bean", IJavaSearchConstants.ANNOTATION_TYPE, IJavaSearchConstants.ANNOTATION_TYPE_REFERENCE, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE); SearchPattern importPattern = SearchPattern.createPattern("org.springframework.context.annotation.Import", IJavaSearchConstants.ANNOTATION_TYPE, IJavaSearchConstants.ANNOTATION_TYPE_REFERENCE, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE); SearchPattern enableAutoConfigPattern = SearchPattern.createPattern("org.springframework.boot.autoconfigure.EnableAutoConfiguration", IJavaSearchConstants.ANNOTATION_TYPE, IJavaSearchConstants.ANNOTATION_TYPE_REFERENCE, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE); SearchPattern bootAutoConfigPattern = SearchPattern.createPattern("org.springframework.boot.autoconfigure.SpringBootApplication", IJavaSearchConstants.ANNOTATION_TYPE, IJavaSearchConstants.ANNOTATION_TYPE_REFERENCE, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE); SearchPattern pattern = SearchPattern.createOrPattern(configurationPattern, componentPattern); pattern = SearchPattern.createOrPattern(pattern, beanPattern); pattern = SearchPattern.createOrPattern(pattern, importPattern); pattern = SearchPattern.createOrPattern(pattern, enableAutoConfigPattern); pattern = SearchPattern.createOrPattern(pattern, bootAutoConfigPattern); return searchForJavaConfigs(pattern, scope); } }