/*******************************************************************************
* Copyright (c) 2013, 2017 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.classreading;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.springframework.asm.Type;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.MethodMetadataReadingVisitor;
import org.springframework.ide.eclipse.core.java.JdtUtils;
import org.springframework.ide.eclipse.core.model.java.JavaModelMethodSourceLocation;
import org.springframework.ide.eclipse.core.model.java.JavaModelSourceLocation;
/**
* Addition to the standard class method metadata reading visitor that connects this method metadata to the corresponding
* JDT IMethod
*
* @author Martin Lippert
* @since 3.3.0
*/
public class JdtConnectedMethodMetadataReadingVisitor extends MethodMetadataReadingVisitor implements JdtConnectedMetadata {
private final String desc;
private final String name;
private final IType mainType;
private IMethod method;
public JdtConnectedMethodMetadataReadingVisitor(IType mainType, String name, int access, String desc, String declaringClassName, ClassLoader classLoader,
Set<MethodMetadata> methodMetadataMap, String returnType) {
super(name, access, declaringClassName, returnType, classLoader, methodMetadataMap);
this.mainType = mainType;
this.desc = desc;
this.name = name;
this.method = null;
}
public IJavaElement getJavaElement() {
if (method == null) {
method = getMethodFromSignature(name, desc);
}
return this.method;
}
public JavaModelSourceLocation createSourceLocation() throws JavaModelException {
IJavaElement javaElement = getJavaElement();
if (javaElement == null) {
throw new NullPointerException("java element not found for: " + this.name + " - with desc: " + this.desc + " - on main type: " + mainType != null ? mainType.getElementName() : "null");
}
else {
return new JavaModelMethodSourceLocation(javaElement, getReturnTypeName());
}
}
private IMethod getMethodFromSignature(final String name, final String desc) {
if (System.getProperty("spring-tooling.scanning.verbose", "false").equals("true")) {
System.out.println("spring-tooling.scanning - findMethodFromSignature - type: " + this.mainType.getFullyQualifiedName() + " - method: " + name + " - signature: " + desc);
}
Type[] parameterTypes = Type.getArgumentTypes(desc);
IMethod method = null;
if (isConstructor(name)) {
method = quickCheckForConstructor(parameterTypes);
} else {
method = quickCheckForMethod(name, parameterTypes);
}
if (method == null) {
List<String> parameters = new ArrayList<String>();
if (parameterTypes != null && parameterTypes.length > 0) {
for (Type parameterType : parameterTypes) {
parameters.add(parameterType.getClassName());
}
}
if (isConstructor(name)) {
method = JdtUtils.getConstructor(mainType, parameters.toArray(new String[parameters.size()]));
} else {
if (System.getProperty("spring-tooling.scanning.verbose", "false").equals("true")) {
System.out.println("spring-tooling.scanning - deep dive to find method - type: " + this.mainType.getFullyQualifiedName() + " - method: " + name + " - signature: " + desc);
}
method = JdtUtils.getMethod(mainType, name, parameters.toArray(new String[parameters.size()]), false);
}
}
return method;
}
private boolean isConstructor(String name) {
return "<init>".equals(name);
}
private IMethod quickCheckForMethod(String name, Type[] parameterTypes) {
IMethod result = null;
try {
IMethod[] methods = mainType.getMethods();
for (IMethod method : methods) {
if (method.getElementName().equals(name) && method.getParameterTypes().length == parameterTypes.length) {
if (result == null) {
result = method;
} else {
return null;
}
}
}
} catch (JavaModelException e) {
}
return result;
}
private IMethod quickCheckForConstructor(Type[] parameterTypes) {
IMethod result = null;
try {
IMethod[] methods = mainType.getMethods();
for (IMethod method : methods) {
if (method.isConstructor() && method.getParameterTypes().length == parameterTypes.length) {
if (result == null) {
result = method;
} else {
return null;
}
}
}
} catch (JavaModelException e) {
}
return result;
}
}