101 lines
4.0 KiB
Java
101 lines
4.0 KiB
Java
package com.example.statemachinedemo;
|
|
|
|
import org.eclipse.jdt.core.dom.*;
|
|
|
|
import java.util.List;
|
|
|
|
public class StateMachineConfigureMethodFinder {
|
|
/**
|
|
* Parses source code and returns the MethodDeclaration for
|
|
* `public void configure(StateMachineTransitionConfigurer<T,D> transitions) throws Exception`
|
|
* in a class extending StateMachineConfigurerAdapter.
|
|
*
|
|
* @param source Java source code string
|
|
* @return MethodDeclaration of configure or null if not found
|
|
*/
|
|
public static MethodDeclaration findConfigureMethod(String source) {
|
|
ASTParser parser = ASTParser.newParser(AST.JLS17);
|
|
parser.setSource(source.toCharArray());
|
|
parser.setKind(ASTParser.K_COMPILATION_UNIT);
|
|
parser.setResolveBindings(false);
|
|
|
|
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
|
|
|
|
ConfigureMethodVisitor visitor = new ConfigureMethodVisitor();
|
|
cu.accept(visitor);
|
|
|
|
return visitor.getConfigureMethod();
|
|
}
|
|
|
|
private static class ConfigureMethodVisitor extends ASTVisitor {
|
|
private MethodDeclaration configureMethod = null;
|
|
|
|
@Override
|
|
public boolean visit(TypeDeclaration node) {
|
|
// Check if class extends StateMachineConfigurerAdapter
|
|
if (!node.isInterface() && extendsStateMachineConfigurerAdapter(node)) {
|
|
// Look for configure method inside this class
|
|
for (MethodDeclaration method : node.getMethods()) {
|
|
if (isConfigureMethod(method)) {
|
|
configureMethod = method;
|
|
return false; // Found, stop visiting further
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private boolean extendsStateMachineConfigurerAdapter(TypeDeclaration node) {
|
|
Type superclass = node.getSuperclassType();
|
|
if (superclass == null) return false;
|
|
|
|
// Superclass can be parameterized type
|
|
if (superclass.isParameterizedType()) {
|
|
ParameterizedType pt = (ParameterizedType) superclass;
|
|
String superName = pt.getType().toString();
|
|
return superName.equals("StateMachineConfigurerAdapter");
|
|
} else {
|
|
return superclass.toString().equals("StateMachineConfigurerAdapter");
|
|
}
|
|
}
|
|
|
|
private boolean isConfigureMethod(MethodDeclaration method) {
|
|
if (!method.getName().getIdentifier().equals("configure")) return false;
|
|
|
|
// Must be public void
|
|
if (!Modifier.isPublic(method.getModifiers())) return false;
|
|
if (!(method.getReturnType2() != null && method.getReturnType2().isPrimitiveType())) return false;
|
|
if (!"void".equals(method.getReturnType2().toString())) return false;
|
|
|
|
// Exactly one parameter of type StateMachineTransitionConfigurer<T,D>
|
|
List<?> params = method.parameters();
|
|
if (params.size() != 1) return false;
|
|
|
|
SingleVariableDeclaration param = (SingleVariableDeclaration) params.get(0);
|
|
Type paramType = param.getType();
|
|
|
|
String paramTypeStr = paramType.toString();
|
|
|
|
// Since generic params, just check starts with StateMachineTransitionConfigurer
|
|
if (!paramTypeStr.startsWith("StateMachineTransitionConfigurer")) return false;
|
|
|
|
// Check throws Exception using thrownExceptionTypes()
|
|
@SuppressWarnings("unchecked")
|
|
List<Type> thrownExceptions = method.thrownExceptionTypes();
|
|
boolean throwsExceptionFound = false;
|
|
for (Type excType : thrownExceptions) {
|
|
if (excType.toString().equals("Exception")) {
|
|
throwsExceptionFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!throwsExceptionFound) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public MethodDeclaration getConfigureMethod() {
|
|
return configureMethod;
|
|
}
|
|
}
|
|
} |