package com.yourpackage;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.SmartLifecycle;
import java.util.HashSet;
import java.util.Set;
public class SpringVisualizer implements ApplicationContextAware, SmartLifecycle {
private ConfigurableApplicationContext startContext;
private boolean isRunning = false;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.startContext = (ConfigurableApplicationContext) applicationContext;
}
@Override
public void start() {
System.out.println("\n=== GENERATING ESCAPED PROPERTY GRAPH ===");
generateSafeGraph();
this.isRunning = true;
}
private void generateSafeGraph() {
StringBuilder dot = new StringBuilder("digraph SafeBeanMap {\n");
// We use 'Mrecord' for rounded corners and better text alignment
dot.append(" rankdir=LR; node [shape=Mrecord, style=filled, fillcolor=\"#E1F5FE\", fontname=\"Arial\", fontsize=9];\n");
Set<String> processed = new HashSet<>();
ApplicationContext current = this.startContext;
while (current != null) {
ConfigurableListableBeanFactory factory = ((ConfigurableApplicationContext) current).getBeanFactory();
for (String name : factory.getBeanDefinitionNames()) {
if (processed.add(name)) {
BeanDefinition def = factory.getBeanDefinition(name);
// Header: Bean Name
StringBuilder label = new StringBuilder();
label.append("{ ").append(clean(name));
// Body: Properties
PropertyValue[] pvs = def.getPropertyValues().getPropertyValues();
if (pvs.length > 0) {
label.append(" | ");
for (PropertyValue pv : pvs) {
String val = String.valueOf(pv.getValue());
// Limit length to prevent massive boxes
if (val.length() > 40) val = val.substring(0, 37) + "...";
label.append(clean(pv.getName())).append("=").append(clean(val)).append("\\l");
}
}
label.append(" }");
// Node Color Logic
String color = "#E1F5FE";
if (name.toLowerCase().contains("comet")) color = "#FFF9C4";
if (name.toLowerCase().contains("cpls")) color = "#C8E6C9";
dot.append(String.format(" \"%s\" [label=\"%s\", fillcolor=\"%s\"];\n", clean(name), label.toString(), color));
// Edges
for (String dep : factory.getDependenciesForBean(name)) {
dot.append(String.format(" \"%s\" -> \"%s\";\n", clean(name), clean(dep)));
}
}
}
current = current.getParent();
}
dot.append("}\n");
System.out.println("----- COPY START -----");
System.out.println(dot.toString());
System.out.println("----- COPY END -----");
}
/**
* Escapes characters that break Graphviz Record shapes
*/
private String clean(String input) {
if (input == null) return "null";
return input.replace("\"", "'")
.replace("{", "\\{")
.replace("}", "\\}")
.replace("|", "\\|")
.replace("<", "\\<")
.replace(">", "\\>")
.replace("\n", " ")
.replace("\r", " ");
}
@Override public int getPhase() { return Integer.MAX_VALUE; }
@Override public boolean isAutoStartup() { return true; }
@Override public void stop() { this.isRunning = false; }
@Override public boolean isRunning() { return this.isRunning; }
@Override public void stop(Runnable callback) { callback.run(); }
}
For further actions, you may consider blocking this person and/or reporting abuse
Top comments (0)