/*******************************************************************************
* 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);
}
}