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 private int extensionsCount = 0;
64 public ClassDescriptor(final Class<? extends Object> clazz,
65 final ClassGraph dump) {
68 fullyQualifiedName = clazz.getName();
69 dump.nameToClassMap.put(fullyQualifiedName, this);
71 isArray = clazz.isArray();
74 final Class<?> componentType = clazz.getComponentType();
75 dump.addClass(componentType);
78 // System.out.println("class: " + fullyQualifiedName);
80 isEnum = clazz.isEnum();
82 isInterface = clazz.isInterface();
87 indexFields(clazz.getDeclaredFields());
88 indexFields(clazz.getFields());
92 for (final Class interfaceClass : clazz.getInterfaces()) {
93 final ClassDescriptor classDescriptor = dump
94 .addClass(interfaceClass);
95 classDescriptor.registerExtension();
96 interfaces.add(classDescriptor);
99 superClass = dump.addClass(clazz.getSuperclass());
100 if (superClass != null)
101 superClass.registerExtension();
105 public boolean areReferencesShown() {
106 return incomingReferencesCount <= MAX_REFERECNES_COUNT;
109 public void enlistFieldReferences(final StringBuffer result) {
110 if (nameToFieldMap.isEmpty())
114 result.append(" // field references to other classes\n");
115 for (final Map.Entry<String, FieldDescriptor> entry : nameToFieldMap
117 result.append(entry.getValue().getDot());
120 public void enlistFields(final StringBuffer result) {
121 if (nameToFieldMap.isEmpty())
125 result.append(" // fields:\n");
128 for (final Map.Entry<String, FieldDescriptor> entry : nameToFieldMap
130 result.append(entry.getValue().getEmbeddedDot());
133 public void enlistImplementedInterfaces(final StringBuffer result) {
134 if (interfaces.isEmpty())
138 result.append(" // interfaces implemented by class: "
139 + fullyQualifiedName + "\n");
141 for (final ClassDescriptor interfaceDescriptor : interfaces) {
142 if (!interfaceDescriptor.isVisible())
145 result.append(" " + interfaceDescriptor.getGraphId() + " -> "
146 + getGraphId() + "[style=\"dotted, tapered\", color=\""
147 + interfaceDescriptor.getInterfaceColor()
148 + "\", penwidth=20, dir=\"forward\"];\n");
152 public void enlistMethodReferences(final StringBuffer result) {
153 if (methods.isEmpty())
157 result.append(" // method references to other classes\n");
158 for (final MethodDescriptor methodDescriptor : methods)
159 result.append(methodDescriptor.getDot());
162 public void enlistMethods(final StringBuffer result) {
163 if (methods.isEmpty())
167 result.append(" // methods:\n");
170 for (final MethodDescriptor methodDescriptor : methods)
171 result.append(methodDescriptor.getEmbeddedDot());
174 public void enlistSuperClass(final StringBuffer result) {
175 if (superClass == null)
178 if (!superClass.isVisible())
182 result.append(" // super class for: " + fullyQualifiedName + "\n");
184 result.append(" " + superClass.getGraphId() + " -> " + getGraphId()
185 + "[style=\"tapered\", color=\""
186 + superClass.getSuperClassColor()
187 + "\", penwidth=10, dir=\"forward\"];\n");
190 public void generateDotHeader(final StringBuffer result) {
192 result.append("// Class: " + fullyQualifiedName + "\n");
194 result.append(" " + getGraphId() + "[label=<<TABLE "
195 + getBackgroundColor() + " BORDER=\"" + getBorderWidth()
196 + "\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n");
199 result.append(" // class descriptor header\n");
200 result.append(" <TR><TD colspan=\"2\" PORT=\"f0\">"
201 + "<FONT POINT-SIZE=\"8.0\" >" + getPackageName()
204 final String parentClassesName = getParentClassesName();
205 if (parentClassesName.length() > 0)
206 result.append("<FONT POINT-SIZE=\"12.0\"><B>" + parentClassesName
207 + "</B></FONT><br/>\n");
209 result.append("<FONT POINT-SIZE=\"25.0\"><B>" + getClassName(false)
210 + "</B></FONT>" + "</TD></TR>\n");
213 public List<FieldDescriptor> getAllFields() {
214 final List<FieldDescriptor> result = new ArrayList<FieldDescriptor>();
216 for (final Map.Entry<String, FieldDescriptor> entry : nameToFieldMap
218 result.add(entry.getValue());
223 public String getBackgroundColor() {
227 bgColor = "bgcolor=\"navajowhite2\"";
230 bgColor = "bgcolor=\"darkslategray1\"";
235 public String getBorderWidth() {
237 if (!areReferencesShown())
242 public String getClassName(final boolean differentiateArray) {
243 // this is needed for nested classes
244 final String actualClassName = fullyQualifiedName.replace('$', '.');
246 final int i = actualClassName.lastIndexOf('.');
248 String result = actualClassName.substring(i + 1);
251 result = result.substring(0, result.length() - 1);
253 if (differentiateArray)
257 // this is needed for nested classes
258 // result = result.replace('$', '.');
262 public String getColor() {
263 if (getDistinctiveColor() == null)
264 setDistinctiveColor(Utils.getNextDarkColor());
266 return getDistinctiveColor();
269 public String getDistinctiveColor() {
270 return distinctiveReferenceColor;
274 public String getDot() {
281 final StringBuffer result = new StringBuffer();
283 generateDotHeader(result);
285 enlistFields(result);
287 enlistMethods(result);
289 result.append(" </TABLE>>, shape=\"none\"];\n");
291 enlistFieldReferences(result);
293 enlistMethodReferences(result);
295 enlistImplementedInterfaces(result);
297 enlistSuperClass(result);
299 return result.toString();
303 public String getEmbeddedDot() {
308 public String getGraphId() {
309 final String result = "class_"
310 + fullyQualifiedName.replace('.', '_').replace(";", "")
311 .replace("[L", "").replace('$', '_');
315 public String getInterfaceColor() {
316 if (interfaceColor == null)
317 interfaceColor = Utils.getNextLightColor();
319 return interfaceColor;
322 private int getOutgoingReferencesCount() {
325 // count method references
326 for (final MethodDescriptor methodDescriptor : methods)
327 result += methodDescriptor.getOutsideVisibleReferencesCount();
329 // count field references
330 for (final FieldDescriptor fieldDescriptor : nameToFieldMap.values())
331 result += fieldDescriptor.getOutsideVisibleReferencesCount();
333 // count implemented interfaces
334 for (final ClassDescriptor classDescriptor : interfaces)
335 if (classDescriptor.isVisible())
339 if (superClass != null)
340 if (superClass.isVisible())
346 public String getPackageName() {
348 final int i = fullyQualifiedName.lastIndexOf('.');
353 return fullyQualifiedName.substring(0, i).replace("[L", "");
356 // public String getReadableName() {
358 // // do not print full class name for well known system classes
359 // final String packageName = getPackageName();
361 // if (packageName.equals("java.util"))
362 // return getClassName();
364 // if (packageName.equals("java.lang"))
365 // return getClassName();
367 // return fullyQualifiedName;
370 public String getParentClassesName() {
371 int i = fullyQualifiedName.lastIndexOf('.');
372 final String fullClassName = fullyQualifiedName.substring(i + 1);
374 i = fullClassName.lastIndexOf('$');
377 final String parentClassesName = fullClassName.substring(0, i);
378 return parentClassesName.replace('$', '.');
381 public String getSuperClassColor() {
382 if (superClassColor == null)
383 superClassColor = Utils.getNextLightColor();
385 return superClassColor;
392 public void hideClassIfNoReferences() {
396 final int totalReferencesCount = getOutgoingReferencesCount()
397 + incomingReferencesCount + extensionsCount;
399 if (totalReferencesCount == 0) {
407 public void indexFields(final Field[] fields) {
408 for (final Field field : fields) {
409 if (nameToFieldMap.containsKey(field.getName()))
412 final FieldDescriptor fieldDescriptor = new FieldDescriptor(field,
418 private void indexMethods(final Class<? extends Object> clazz) {
419 final Method[] methods = clazz.getMethods();
421 for (final Method method : methods)
422 new MethodDescriptor(method, this, classGraph);
427 public boolean isVisible() {
429 if (Utils.isSystemDataType(fullyQualifiedName))
432 if (Utils.isSystemPackage(fullyQualifiedName))
435 if (!classGraph.getFilter().isClassShown(fullyQualifiedName))
442 * Register event when another class is extending this one, or is
443 * implementing interface declared by this class.
445 public void registerExtension() {
449 public void registerReference() {
450 incomingReferencesCount++;
453 public void setDistinctiveColor(final String distinctiveColor) {
454 distinctiveReferenceColor = distinctiveColor;