Files
spring-state-machine-renderer/src/main/java/com/example/statemachinedemo/StateMachineConfigureMethodFinder.java
2025-07-13 15:39:40 +02:00

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;
}
}
}