name collision tests
This commit is contained in:
@@ -29,7 +29,7 @@ public class Main {
|
||||
private static final String OUTPUT_DIR = "./out";
|
||||
private static final String EXTENSION = ".java";
|
||||
private static final List<String> TARGET_ANNOTATIONS = List.of("EnableStateMachineFactory", "EnableStateMachine");
|
||||
public static final Set<String> STATE_MACHINE_RETURN_TYPES = Set.of("StateMachine");
|
||||
public static final Set<String> STATE_MACHINE_RETURN_TYPES = Set.of("StateMachine", "StateMachineFactory", "StateMachineModelFactory");
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
runExporter(Path.of(START_DIR), Path.of(OUTPUT_DIR));
|
||||
@@ -46,27 +46,36 @@ public class Main {
|
||||
);
|
||||
|
||||
exportAll(context, outputs, outputDir);
|
||||
|
||||
// Still handle methods returning StateMachine for now (might be harder to refactor to CodebaseContext)
|
||||
AstFileFinder finder = new AstFileFinder();
|
||||
List<Path> javaFiles = FileUtils.findFilesWithExtension(Set.of(inputDir), EXTENSION);
|
||||
for (Path javaFile : javaFiles) {
|
||||
String source = Files.readString(javaFile);
|
||||
if (finder.hasFunctionReturningType(source, STATE_MACHINE_RETURN_TYPES)) {
|
||||
processReturnTypeFoundSource(source, javaFile, outputs, outputDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void exportAll(CodebaseContext context, List<StateMachineExporter> outputs, Path outputDir) throws IOException {
|
||||
Set<String> processedLocations = new HashSet<>();
|
||||
|
||||
// 1. Find entry point classes (annotated or extending adapter)
|
||||
List<TypeDeclaration> entryPoints = context.findEntryPointClasses(TARGET_ANNOTATIONS);
|
||||
for (TypeDeclaration td : entryPoints) {
|
||||
processEntryPoint(td, outputs, outputDir, context);
|
||||
String fqn = context.getFqn(td);
|
||||
if (processedLocations.add(fqn)) {
|
||||
processEntryPoint(td, outputs, outputDir, context);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Find methods returning StateMachine beans
|
||||
List<MethodDeclaration> beanMethods = context.findBeanMethodsReturning(STATE_MACHINE_RETURN_TYPES);
|
||||
for (MethodDeclaration m : beanMethods) {
|
||||
TypeDeclaration parentClass = (TypeDeclaration) m.getParent();
|
||||
String parentFqn = context.getFqn(parentClass);
|
||||
String methodName = m.getName().getIdentifier();
|
||||
String uniqueId = parentFqn + "#" + methodName;
|
||||
|
||||
if (processedLocations.add(uniqueId)) {
|
||||
processBeanMethod(m, outputs, outputDir, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void processEntryPoint(TypeDeclaration td, List<StateMachineExporter> outputs, Path outputDir, CodebaseContext context) throws IOException {
|
||||
String className = td.getName().getFullyQualifiedName();
|
||||
String className = context.getFqn(td);
|
||||
System.out.println("Processing state machine config: " + className);
|
||||
|
||||
StateMachineAggregator aggregator = new StateMachineAggregator(context);
|
||||
@@ -85,23 +94,20 @@ public class Main {
|
||||
generateOutputs(outputDir, className, transitions, startStates, endStates, outputs);
|
||||
}
|
||||
|
||||
static void processReturnTypeFoundSource(String source, Path javaFile, List<StateMachineExporter> outputs, Path outputDir) throws IOException {
|
||||
Set<MethodDeclaration> methodsWithReturnType = new StateMachineTransitionConfigurationMethodFinder(source).findMethodsWithReturnType(STATE_MACHINE_RETURN_TYPES);
|
||||
if (!methodsWithReturnType.isEmpty()) {
|
||||
for (MethodDeclaration m : methodsWithReturnType) {
|
||||
System.out.println("Found method returning StateMachine in: " + javaFile.toAbsolutePath());
|
||||
List<Transition> transitions = AstTransitionParser.parseTransitions(m);
|
||||
|
||||
Set<String> startStatesTransitions = TransitionStateUtils.findStartStates(transitions);
|
||||
Set<String> endStatesTransitions = TransitionStateUtils.findEndStates(transitions);
|
||||
static void processBeanMethod(MethodDeclaration m, List<StateMachineExporter> outputs, Path outputDir, CodebaseContext context) throws IOException {
|
||||
TypeDeclaration parentClass = (TypeDeclaration) m.getParent();
|
||||
String parentFqn = context.getFqn(parentClass);
|
||||
String methodName = m.getName().getIdentifier();
|
||||
String uniqueName = parentFqn + "#" + methodName;
|
||||
|
||||
Set<String> startStates = new HashSet<>(startStatesTransitions);
|
||||
Set<String> endStates = new HashSet<>(endStatesTransitions);
|
||||
System.out.println("Processing state machine bean: " + uniqueName);
|
||||
|
||||
List<Transition> transitions = AstTransitionParser.parseTransitions(m);
|
||||
|
||||
Set<String> startStates = TransitionStateUtils.findStartStates(transitions);
|
||||
Set<String> endStates = TransitionStateUtils.findEndStates(transitions);
|
||||
|
||||
String baseName = javaFile.getFileName().toString().replaceFirst("[.][^.]+$", "");
|
||||
generateOutputs(outputDir, baseName, transitions, startStates, endStates, outputs);
|
||||
}
|
||||
}
|
||||
generateOutputs(outputDir, uniqueName, transitions, startStates, endStates, outputs);
|
||||
}
|
||||
|
||||
private static void generateOutputs(Path outputDir, String baseName, List<Transition> transitions,
|
||||
|
||||
@@ -92,6 +92,13 @@ public class CodebaseContext {
|
||||
return getTypeDeclaration(name);
|
||||
}
|
||||
|
||||
public String getFqn(TypeDeclaration td) {
|
||||
CompilationUnit cu = (CompilationUnit) td.getRoot();
|
||||
String packageName = cu.getPackage() != null ? cu.getPackage().getName().getFullyQualifiedName() : "";
|
||||
String simpleName = td.getName().getIdentifier();
|
||||
return packageName.isEmpty() ? simpleName : packageName + "." + simpleName;
|
||||
}
|
||||
|
||||
private TypeDeclaration findTypeInCu(CompilationUnit cu, String fqn) {
|
||||
String packageName = cu.getPackage() != null ? cu.getPackage().getName().getFullyQualifiedName() : "";
|
||||
for (Object type : cu.types()) {
|
||||
@@ -169,9 +176,42 @@ public class CodebaseContext {
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<MethodDeclaration> findBeanMethodsReturning(Set<String> targetReturnTypes) {
|
||||
List<MethodDeclaration> beanMethods = new ArrayList<>();
|
||||
for (CompilationUnit cu : classes.values()) {
|
||||
for (Object type : cu.types()) {
|
||||
if (type instanceof TypeDeclaration td) {
|
||||
for (MethodDeclaration method : td.getMethods()) {
|
||||
if (isBeanMethodReturning(method, targetReturnTypes)) {
|
||||
beanMethods.add(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return beanMethods;
|
||||
}
|
||||
|
||||
private boolean isBeanMethodReturning(MethodDeclaration method, Set<String> targetReturnTypes) {
|
||||
// Check return type
|
||||
Type returnType = method.getReturnType2();
|
||||
if (returnType == null) return false;
|
||||
String typeName = AstUtils.extractSimpleTypeName(returnType);
|
||||
if (!targetReturnTypes.contains(typeName)) return false;
|
||||
|
||||
// Check for @Bean annotation
|
||||
for (Object modifier : method.modifiers()) {
|
||||
if (modifier instanceof Annotation annotation) {
|
||||
String annotationName = annotation.getTypeName().getFullyQualifiedName();
|
||||
if ("Bean".equals(annotationName) || "org.springframework.context.annotation.Bean".equals(annotationName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String getSimpleName(Type type) {
|
||||
if (type.isSimpleType()) return ((SimpleType) type).getName().getFullyQualifiedName();
|
||||
if (type.isParameterizedType()) return getSimpleName(((ParameterizedType) type).getType());
|
||||
return type.toString();
|
||||
return AstUtils.extractSimpleTypeName(type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +49,21 @@ public class AstFileFinder {
|
||||
String typeName = (returnType == null) ? "void" : AstUtils.extractSimpleTypeName(returnType);
|
||||
|
||||
if (targetReturnTypes.contains(typeName)) {
|
||||
found.set(true);
|
||||
return false; // stop visiting
|
||||
// Also check for @Bean annotation
|
||||
boolean hasBeanAnnotation = false;
|
||||
for (Object modifier : node.modifiers()) {
|
||||
if (modifier instanceof Annotation annotation) {
|
||||
String annotationName = annotation.getTypeName().getFullyQualifiedName();
|
||||
if ("Bean".equals(annotationName) || "org.springframework.context.annotation.Bean".equals(annotationName)) {
|
||||
hasBeanAnnotation = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasBeanAnnotation) {
|
||||
found.set(true);
|
||||
return false; // stop visiting
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -99,20 +99,34 @@ public class RegressionTest {
|
||||
|
||||
Main.exportAll(context, outputs, tempDir);
|
||||
|
||||
String baseName = scenario.baseName();
|
||||
for (StateMachineExporter exporter : outputs) {
|
||||
String fileName = baseName + exporter.getFileExtension();
|
||||
|
||||
Path actualFile = tempDir.resolve(baseName).resolve(fileName);
|
||||
Path goldenFile = scenario.goldenPath().resolve(fileName);
|
||||
|
||||
assertThat(actualFile)
|
||||
.as("File %s should exist in output", fileName)
|
||||
.exists();
|
||||
|
||||
assertThat(actualFile)
|
||||
.as("Content mismatch for %s", fileName)
|
||||
.hasSameTextualContentAs(goldenFile);
|
||||
// Find the generated directory (it might be named with FQN)
|
||||
List<Path> generatedDirs;
|
||||
try (var stream = Files.list(tempDir)) {
|
||||
generatedDirs = stream.filter(Files::isDirectory).toList();
|
||||
}
|
||||
|
||||
String targetBaseName = scenario.baseName();
|
||||
Path actualDir = generatedDirs.stream()
|
||||
.filter(d -> d.getFileName().toString().endsWith(targetBaseName))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("No output directory found for " + targetBaseName + " in " + generatedDirs));
|
||||
|
||||
String actualBaseName = actualDir.getFileName().toString();
|
||||
|
||||
for (StateMachineExporter exporter : outputs) {
|
||||
String fileName = actualBaseName + exporter.getFileExtension();
|
||||
String goldenFileName = targetBaseName + exporter.getFileExtension();
|
||||
|
||||
Path actualFile = actualDir.resolve(fileName);
|
||||
Path goldenFile = scenario.goldenPath().resolve(goldenFileName);
|
||||
|
||||
assertThat(actualFile)
|
||||
.as("File %s should exist in output", fileName)
|
||||
.exists();
|
||||
|
||||
assertThat(actualFile)
|
||||
.as("Content mismatch for %s", fileName)
|
||||
.hasSameTextualContentAs(goldenFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,6 +277,7 @@ class AstFileFinderTest {
|
||||
void shouldReturnTrue_whenFunctionReturnsTargetType() {
|
||||
String source = """
|
||||
public class Test {
|
||||
@Bean
|
||||
public StateMachine<S, E> build() { return null; }
|
||||
}
|
||||
""";
|
||||
@@ -289,6 +290,7 @@ class AstFileFinderTest {
|
||||
void shouldReturnFalse_whenNoFunctionReturnsTargetType() {
|
||||
String source = """
|
||||
public class Test {
|
||||
@Bean
|
||||
public void build() {}
|
||||
}
|
||||
""";
|
||||
@@ -301,6 +303,7 @@ class AstFileFinderTest {
|
||||
void shouldReturnTrue_whenFunctionReturnsQualifiedTargetType() {
|
||||
String source = """
|
||||
public class Test {
|
||||
@Bean
|
||||
public org.springframework.statemachine.StateMachine build() { return null; }
|
||||
}
|
||||
""";
|
||||
|
||||
Reference in New Issue
Block a user