2 * JavaInspect - Utility to visualize java software
3 * Copyright (C) 2013, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU General Public License
7 * as published by the Free Software Foundation.
10 package eu.svjatoslav.inspector.java.structure;
12 import java.lang.reflect.Field;
13 import java.lang.reflect.Method;
14 import java.util.ArrayList;
15 import java.util.List;
17 import java.util.SortedSet;
18 import java.util.TreeMap;
19 import java.util.TreeSet;
22 * Describes single class instance
24 public class ClassDescriptor implements GraphElement {
26 private static final int MAX_REFERECNES_COUNT = 10;
28 public final String fullyQualifiedName;
30 Map<String, FieldDescriptor> nameToFieldMap = new TreeMap<String, FieldDescriptor>();
32 public SortedSet<MethodDescriptor> methods = new TreeSet<MethodDescriptor>();
35 * Incoming arrows will have this color.
37 private String distinctiveReferenceColor;
39 private String interfaceColor;
41 private String superClassColor;
49 private boolean isShown = true;
51 private final ClassGraph classGraph;
53 List<ClassDescriptor> interfaces = new ArrayList<ClassDescriptor>();
55 ClassDescriptor superClass;
58 * Amount of field and method references pointing to this class.
60 private int incomingReferencesCount = 0;
62 public ClassDescriptor(final Class<? extends Object> clazz,
63 final ClassGraph dump) {
66 fullyQualifiedName = clazz.getName();
67 dump.nameToClassMap.put(fullyQualifiedName, this);
69 isArray = clazz.isArray();
72 final Class<?> componentType = clazz.getComponentType();
73 dump.addClass(componentType);
76 // System.out.println("class: " + fullyQualifiedName);
78 isEnum = clazz.isEnum();
80 isInterface = clazz.isInterface();
85 indexFields(clazz.getDeclaredFields());
86 indexFields(clazz.getFields());
90 for (final Class interfaceClass : clazz.getInterfaces())
91 interfaces.add(dump.addClass(interfaceClass));
93 superClass = dump.addClass(clazz.getSuperclass());
96 public boolean areReferencesShown() {
97 return incomingReferencesCount <= MAX_REFERECNES_COUNT;
100 public void enlistFieldReferences(final StringBuffer result) {
101 if (nameToFieldMap.isEmpty())
105 result.append(" // field references to other classes\n");
106 for (final Map.Entry<String, FieldDescriptor> entry : nameToFieldMap
108 result.append(entry.getValue().getDot());
111 public void enlistFields(final StringBuffer result) {
112 if (nameToFieldMap.isEmpty())
116 result.append(" // fields:\n");
119 for (final Map.Entry<String, FieldDescriptor> entry : nameToFieldMap
121 result.append(entry.getValue().getEmbeddedDot());
124 public void enlistImplementedInterfaces(final StringBuffer result) {
125 if (interfaces.isEmpty())
129 result.append(" // interfaces implemented by class: "
130 + fullyQualifiedName + "\n");
132 for (final ClassDescriptor interfaceDescriptor : interfaces) {
133 if (!interfaceDescriptor.isVisible())
136 result.append(" " + interfaceDescriptor.getGraphId() + " -> "
137 + getGraphId() + "[style=\"dotted, tapered\", color=\""
138 + interfaceDescriptor.getInterfaceColor()
139 + "\", penwidth=20, dir=\"forward\"];\n");
143 public void enlistMethodReferences(final StringBuffer result) {
144 if (methods.isEmpty())
148 result.append(" // method references to other classes\n");
149 for (final MethodDescriptor methodDescriptor : methods)
150 result.append(methodDescriptor.getDot());
153 public void enlistMethods(final StringBuffer result) {
154 if (methods.isEmpty())
158 result.append(" // methods:\n");
161 for (final MethodDescriptor methodDescriptor : methods)
162 result.append(methodDescriptor.getEmbeddedDot());
165 public void enlistSuperClass(final StringBuffer result) {
166 if (superClass == null)
169 if (!superClass.isVisible())
173 result.append(" // super class for: " + fullyQualifiedName + "\n");
175 result.append(" " + superClass.getGraphId() + " -> " + getGraphId()
176 + "[style=\"tapered\", color=\""
177 + superClass.getSuperClassColor()
178 + "\", penwidth=10, dir=\"forward\"];\n");
181 public void generateDotHeader(final StringBuffer result) {
183 result.append("// Class: " + fullyQualifiedName + "\n");
185 result.append(" " + getGraphId() + "[label=<<TABLE "
186 + getBackgroundColor() + " BORDER=\"" + getBorderWidth()
187 + "\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n");
190 result.append(" // class descriptor header\n");
191 result.append(" <TR><TD colspan=\"2\" PORT=\"f0\">"
192 + "<FONT POINT-SIZE=\"8.0\" >" + getPackageName()
195 final String parentClassesName = getParentClassesName();
196 if (parentClassesName.length() > 0)
197 result.append("<FONT POINT-SIZE=\"12.0\"><B>" + parentClassesName
198 + "</B></FONT><br/>\n");
200 result.append("<FONT POINT-SIZE=\"25.0\"><B>" + getClassName(false)
201 + "</B></FONT>" + "</TD></TR>\n");
204 public List<FieldDescriptor> getAllFields() {
205 final List<FieldDescriptor> result = new ArrayList<FieldDescriptor>();
207 for (final Map.Entry<String, FieldDescriptor> entry : nameToFieldMap
209 result.add(entry.getValue());
214 public String getBackgroundColor() {
218 bgColor = "bgcolor=\"navajowhite2\"";
221 bgColor = "bgcolor=\"darkslategray1\"";
226 public String getBorderWidth() {
228 if (!areReferencesShown())
233 public String getClassName(final boolean differentiateArray) {
234 // this is needed for nested classes
235 final String actualClassName = fullyQualifiedName.replace('$', '.');
237 final int i = actualClassName.lastIndexOf('.');
239 String result = actualClassName.substring(i + 1);
242 result = result.substring(0, result.length() - 1);
244 if (differentiateArray)
248 // this is needed for nested classes
249 // result = result.replace('$', '.');
253 public String getColor() {
254 if (getDistinctiveColor() == null)
255 setDistinctiveColor(Utils.getNextDarkColor());
257 return getDistinctiveColor();
260 public String getDistinctiveColor() {
261 return distinctiveReferenceColor;
265 public String getDot() {
272 final StringBuffer result = new StringBuffer();
274 generateDotHeader(result);
276 enlistFields(result);
278 enlistMethods(result);
280 result.append(" </TABLE>>, shape=\"none\"];\n");
282 enlistFieldReferences(result);
284 enlistMethodReferences(result);
286 enlistImplementedInterfaces(result);
288 enlistSuperClass(result);
290 return result.toString();
294 public String getEmbeddedDot() {
299 public String getGraphId() {
300 final String result = "class_"
301 + fullyQualifiedName.replace('.', '_').replace(";", "")
302 .replace("[L", "").replace('$', '_');
306 public String getInterfaceColor() {
307 if (interfaceColor == null)
308 interfaceColor = Utils.getNextLightColor();
310 return interfaceColor;
313 public String getPackageName() {
315 final int i = fullyQualifiedName.lastIndexOf('.');
320 return fullyQualifiedName.substring(0, i).replace("[L", "");
323 public String getParentClassesName() {
324 int i = fullyQualifiedName.lastIndexOf('.');
325 final String fullClassName = fullyQualifiedName.substring(i + 1);
327 i = fullClassName.lastIndexOf('$');
330 final String parentClassesName = fullClassName.substring(0, i);
331 return parentClassesName.replace('$', '.');
334 // public String getReadableName() {
336 // // do not print full class name for well known system classes
337 // final String packageName = getPackageName();
339 // if (packageName.equals("java.util"))
340 // return getClassName();
342 // if (packageName.equals("java.lang"))
343 // return getClassName();
345 // return fullyQualifiedName;
348 public String getSuperClassColor() {
349 if (superClassColor == null)
350 superClassColor = Utils.getNextLightColor();
352 return superClassColor;
359 public boolean hideClassIfNoReferences() {
363 int outgoingVisibleReferencesCount = 0;
365 for (final MethodDescriptor methodDescriptor : methods)
366 outgoingVisibleReferencesCount += methodDescriptor
367 .getOutsideVisibleReferencesCount();
369 for (final FieldDescriptor fieldDescriptor : nameToFieldMap.values())
370 outgoingVisibleReferencesCount += fieldDescriptor
371 .getOutsideVisibleReferencesCount();
373 final int totalReferencesCount = outgoingVisibleReferencesCount
374 + incomingReferencesCount;
376 if (totalReferencesCount == 0) {
384 public void indexFields(final Field[] fields) {
385 for (final Field field : fields) {
386 if (nameToFieldMap.containsKey(field.getName()))
389 final FieldDescriptor fieldDescriptor = new FieldDescriptor(field,
395 private void indexMethods(final Class<? extends Object> clazz) {
396 final Method[] methods = clazz.getMethods();
398 for (final Method method : methods)
399 new MethodDescriptor(method, this, classGraph);
404 public boolean isVisible() {
406 if (Utils.isSystemDataType(fullyQualifiedName))
409 if (Utils.isSystemPackage(fullyQualifiedName))
412 if (!classGraph.getFilter().isClassShown(fullyQualifiedName))
418 public void registerReference() {
419 incomingReferencesCount++;
422 public void setDistinctiveColor(final String distinctiveColor) {
423 distinctiveReferenceColor = distinctiveColor;