package ${packageName};
import org.springframework.context.*;
import org.springframework.beans.factory.config.*;
import java.io.FileWriter;
import java.util.*;
public class SpringVisualizer implements ApplicationContextAware, SmartLifecycle {
private ConfigurableApplicationContext context;
private boolean isRunning = false;
private static final java.util.concurrent.atomic.AtomicBoolean hasFired = new java.util.concurrent.atomic.AtomicBoolean(false);
@Override public void setApplicationContext(ApplicationContext ctx) { this.context = (ConfigurableApplicationContext) ctx; }
@Override
public void start() {
if (!hasFired.compareAndSet(false, true)) return;
try {
StringBuilder dot = new StringBuilder("digraph G {\n");
// LR rankdir and specific spacing to match your 'original' clean look
dot.append(" rankdir=LR; nodesep=0.5; ranksep=2.0; splines=true;\n");
dot.append(" node [shape=none, fontname=\"Arial\", fontsize=10];\n");
ConfigurableListableBeanFactory factory = context.getBeanFactory();
for (String name : factory.getBeanDefinitionNames()) {
if (name.startsWith("org.springframework") || name.startsWith("internal")) continue;
// FIXEDSIZE and WIDTH stop the text from bleeding out of the boxes
dot.append(" \"").append(name).append("\" [label=<<TABLE BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"4\">");
dot.append("<TR><TD BGCOLOR=\"#A0A0A0\" FIXEDSIZE=\"TRUE\" WIDTH=\"250\" HEIGHT=\"25\"><B>")
.append(name).append("</B></TD></TR></TABLE>>];\n");
// Connectivity: checking both directions to ensure all arrows are captured
Set<String> deps = new HashSet<>();
deps.addAll(Arrays.asList(factory.getDependenciesForBean(name)));
deps.addAll(Arrays.asList(factory.getDependentBeans(name)));
for (String dep : deps) {
if (!dep.startsWith("org.springframework")) {
dot.append(" \"").append(name).append("\" -> \"").append(dep).append("\";\n");
}
}
}
dot.append("}\n");
try (FileWriter fw = new FileWriter("build/spring-beans.dot")) {
fw.write(dot.toString());
}
System.out.println(">>> SpringVisualizer: Created build/spring-beans.dot");
} catch (Exception e) { e.printStackTrace(); }
this.isRunning = true;
}
@Override public void stop() { this.isRunning = false; }
@Override public boolean isRunning() { return this.isRunning; }
@Override public int getPhase() { return Integer.MAX_VALUE; }
@Override public boolean isAutoStartup() { return true; }
@Override public void stop(Runnable c) { stop(); c.run(); }
}
==================
// Ensure the project has an extension property to track modified files
project.ext.injectedXmlFiles = []
// TASK 1: Generate Source from Template
task generateSpringVisualizer {
def templateFile = file("gradle/templates/SpringVisualizer.java.template")
def outputDir = file("${buildDir}/generated/sources/visualizer/java/com/yourpackage")
def outputFile = file("${outputDir}/SpringVisualizer.java")
inputs.file(templateFile)
outputs.file(outputFile)
doLast {
outputDir.mkdirs()
copy {
from templateFile
into outputDir
rename { "SpringVisualizer.java" }
expand(packageName: "com.yourpackage")
}
}
}
// Ensure generated code is part of the build
sourceSets.main.java.srcDir "${buildDir}/generated/sources/visualizer/java"
compileJava.dependsOn generateSpringVisualizer
// TASK 2: Dynamic XML Injection (Asset-Agnostic)
task injectVisualizerToXML {
doLast {
// Safety Gate: Only inject if compilation succeeded
def classFile = file("${buildDir}/classes/java/main/com/yourpackage/SpringVisualizer.class")
if (!classFile.exists()) return
// We use the name of the run task to find the right sub-folder
def targetTask = "cash_riobridge"
def configRoot = file("src/main.config")
configRoot.traverse(type: groovy.io.FileType.FILES, nameFilter: ~/spring-.*\.xml/) { file ->
if (file.path.contains(targetTask)) {
def content = file.text
if (!content.contains("id=\"springVisualizer\"")) {
println ">>> Patching XML: ${file.name}"
def beanDef = '\n \n <bean id="springVisualizer" class="com.yourpackage.SpringVisualizer" lazy-init="false" />'
file.text = content.replace("</beans>", "${beanDef}\n</beans>")
project.injectedXmlFiles << file.absolutePath
}
}
}
}
}
// TASK 3: XML Scrubbing (Content cleanup, not file deletion)
task scrubVisualizerFromXML {
doLast {
project.injectedXmlFiles.each { filePath ->
def xmlFile = file(filePath)
if (xmlFile.exists()) {
// Remove ONLY the block we injected via the comment marker
xmlFile.text = xmlFile.text.replaceAll(/(?s)\s*.*?<bean id="springVisualizer".*?\/>/, "")
println ">>> Scrubbed Visualizer from: ${xmlFile.name}"
}
}
}
}
// TASK 4: Hook into your Local Run Task
tasks.named("cash_riobridge") {
dependsOn injectVisualizerToXML
finalizedBy scrubVisualizerFromXML
}
=====================
For further actions, you may consider blocking this person and/or reporting abuse
Top comments (0)