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 referencesCount = 0;
62 // for interface, counts amount of found implementations
63 private int implementationsCount = 0;
65 // counts amount of times this class is extended
66 private int extensionsCount = 0;
68 public ClassDescriptor(final Class<? extends Object> clazz,
69 final ClassGraph dump) {
72 fullyQualifiedName = clazz.getName();
73 dump.nameToClassMap.put(fullyQualifiedName, this);
75 isArray = clazz.isArray();
78 final Class<?> componentType = clazz.getComponentType();
79 dump.addClass(componentType);
82 // System.out.println("class: " + fullyQualifiedName);
84 isEnum = clazz.isEnum();
86 isInterface = clazz.isInterface();
91 indexFields(clazz.getDeclaredFields());
92 indexFields(clazz.getFields());
96 for (final Class interfaceClass : clazz.getInterfaces()) {
97 final ClassDescriptor classDescriptor = dump
98 .addClass(interfaceClass);
99 classDescriptor.registerImplementation();
100 interfaces.add(classDescriptor);
103 superClass = dump.addClass(clazz.getSuperclass());
104 if (superClass != null)
105 superClass.registerExtension();
109 public boolean areReferencesShown() {
110 return referencesCount <= MAX_REFERECNES_COUNT;
113 public void enlistFieldReferences(final StringBuffer result) {
114 if (nameToFieldMap.isEmpty())
118 result.append(" // field references to other classes\n");
119 for (final Map.Entry<String, FieldDescriptor> entry : nameToFieldMap
121 result.append(entry.getValue().getDot());
124 public void enlistFields(final StringBuffer result) {
125 if (nameToFieldMap.isEmpty())
129 result.append(" // fields:\n");
132 for (final Map.Entry<String, FieldDescriptor> entry : nameToFieldMap
134 result.append(entry.getValue().getEmbeddedDot());
137 public void enlistImplementedInterfaces(final StringBuffer result) {
138 if (interfaces.isEmpty())
142 result.append(" // interfaces implemented by class: "
143 + fullyQualifiedName + "\n");
145 for (final ClassDescriptor interfaceDescriptor : interfaces) {
146 if (!interfaceDescriptor.isVisible())
149 result.append(" " + interfaceDescriptor.getGraphId() + " -> "
150 + getGraphId() + "[style=\"dotted, tapered\", color=\""
151 + interfaceDescriptor.getInterfaceColor()
152 + "\", penwidth=20, dir=\"forward\"];\n");
156 public void enlistMethodReferences(final StringBuffer result) {
157 if (methods.isEmpty())
161 result.append(" // method references to other classes\n");
162 for (final MethodDescriptor methodDescriptor : methods)
163 result.append(methodDescriptor.getDot());
166 public void enlistMethods(final StringBuffer result) {
167 if (methods.isEmpty())
171 result.append(" // methods:\n");
174 for (final MethodDescriptor methodDescriptor : methods)
175 result.append(methodDescriptor.getEmbeddedDot());
178 public void enlistSuperClass(final StringBuffer result) {
179 if (superClass == null)
182 if (!superClass.isVisible())
186 result.append(" // super class for: " + fullyQualifiedName + "\n");
188 result.append(" " + superClass.getGraphId() + " -> " + getGraphId()
189 + "[style=\"tapered\", color=\""
190 + superClass.getSuperClassColor()
191 + "\", penwidth=10, dir=\"forward\"];\n");
194 public void generateDotHeader(final StringBuffer result) {
196 result.append("// Class: " + fullyQualifiedName + "\n");
198 result.append(" " + getGraphId() + "[label=<<TABLE "
199 + getBackgroundColor() + " BORDER=\"" + getBorderWidth()
200 + "\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n");
203 result.append(" // class descriptor header\n");
204 result.append(" <TR><TD colspan=\"2\" PORT=\"f0\">"
205 + "<FONT POINT-SIZE=\"8.0\" >" + getPackageName()
208 final String parentClassesName = getParentClassesName();
209 if (parentClassesName.length() > 0)
210 result.append("<FONT POINT-SIZE=\"12.0\"><B>" + parentClassesName
211 + "</B></FONT><br/>\n");
213 result.append("<FONT POINT-SIZE=\"25.0\"><B>" + getClassName(false)
214 + "</B></FONT>" + "</TD></TR>\n");
217 public List<FieldDescriptor> getAllFields() {
218 final List<FieldDescriptor> result = new ArrayList<FieldDescriptor>();
220 for (final Map.Entry<String, FieldDescriptor> entry : nameToFieldMap
222 result.add(entry.getValue());
227 public String getBackgroundColor() {
231 bgColor = "bgcolor=\"navajowhite2\"";
234 bgColor = "bgcolor=\"darkslategray1\"";
239 public String getBorderWidth() {
241 if (!areReferencesShown())
246 public String getClassName(final boolean differentiateArray) {
247 // this is needed for nested classes
248 final String actualClassName = fullyQualifiedName.replace('$', '.');
250 final int i = actualClassName.lastIndexOf('.');
252 String result = actualClassName.substring(i + 1);
255 result = result.substring(0, result.length() - 1);
257 if (differentiateArray)
261 // this is needed for nested classes
262 // result = result.replace('$', '.');
266 public String getColor() {
267 if (getDistinctiveColor() == null)
268 setDistinctiveColor(Utils.getNextDarkColor());
270 return getDistinctiveColor();
273 public String getDistinctiveColor() {
274 return distinctiveReferenceColor;
278 public String getDot() {
285 final StringBuffer result = new StringBuffer();
287 generateDotHeader(result);
289 enlistFields(result);
291 enlistMethods(result);
293 result.append(" </TABLE>>, shape=\"none\"];\n");
295 enlistFieldReferences(result);
297 enlistMethodReferences(result);
299 enlistImplementedInterfaces(result);
301 enlistSuperClass(result);
303 return result.toString();
307 public String getEmbeddedDot() {
312 * Returns field with given name (case is ignored). Or <code>null</code> if
313 * field is not found.
315 public FieldDescriptor getFieldIgnoreCase(final String fieldToSearch) {
317 for (final String fieldName : nameToFieldMap.keySet())
318 if (fieldToSearch.equalsIgnoreCase(fieldName))
319 return nameToFieldMap.get(fieldName);
325 public String getGraphId() {
326 final String result = "class_"
327 + fullyQualifiedName.replace('.', '_').replace(";", "")
328 .replace("[L", "").replace('$', '_');
332 public String getInterfaceColor() {
333 if (interfaceColor == null)
334 interfaceColor = Utils.getNextLightColor();
336 return interfaceColor;
339 private int getOutgoingReferencesCount() {
342 // count method references
343 for (final MethodDescriptor methodDescriptor : methods)
344 result += methodDescriptor.getOutsideVisibleReferencesCount();
346 // count field references
347 for (final FieldDescriptor fieldDescriptor : nameToFieldMap.values())
348 result += fieldDescriptor.getOutsideVisibleReferencesCount();
350 // count implemented interfaces
351 for (final ClassDescriptor classDescriptor : interfaces)
352 if (classDescriptor.isVisible())
356 if (superClass != null)
357 if (superClass.isVisible())
363 // public String getReadableName() {
365 // // do not print full class name for well known system classes
366 // final String packageName = getPackageName();
368 // if (packageName.equals("java.util"))
369 // return getClassName();
371 // if (packageName.equals("java.lang"))
372 // return getClassName();
374 // return fullyQualifiedName;
377 public String getPackageName() {
379 final int i = fullyQualifiedName.lastIndexOf('.');
384 return fullyQualifiedName.substring(0, i).replace("[L", "");
387 public String getParentClassesName() {
388 int i = fullyQualifiedName.lastIndexOf('.');
389 final String fullClassName = fullyQualifiedName.substring(i + 1);
391 i = fullClassName.lastIndexOf('$');
394 final String parentClassesName = fullClassName.substring(0, i);
395 return parentClassesName.replace('$', '.');
398 public String getSuperClassColor() {
399 if (superClassColor == null)
400 superClassColor = Utils.getNextLightColor();
402 return superClassColor;
406 * Checks if class has field with given name (case is ignored). Returns
407 * <code>true</code> if such field is found.
409 public boolean hasFieldIgnoreCase(final String fieldToSearch) {
411 for (final String fieldName : nameToFieldMap.keySet())
412 if (fieldToSearch.equalsIgnoreCase(fieldName))
422 public void hideClassIfNoReferences() {
426 final int totalReferencesCount = getOutgoingReferencesCount()
427 + referencesCount + extensionsCount + implementationsCount;
429 if (totalReferencesCount == 0) {
437 public void indexFields(final Field[] fields) {
438 for (final Field field : fields) {
439 if (nameToFieldMap.containsKey(field.getName()))
442 final FieldDescriptor fieldDescriptor = new FieldDescriptor(field,
448 private void indexMethods(final Class<? extends Object> clazz) {
449 final Method[] methods = clazz.getMethods();
451 for (final Method method : methods)
452 new MethodDescriptor(method, this, classGraph);
457 public boolean isVisible() {
459 if (Utils.isSystemDataType(fullyQualifiedName))
462 if (Utils.isSystemPackage(fullyQualifiedName))
465 if (!classGraph.getFilter().isClassShown(fullyQualifiedName))
472 * Register event when another class is extending this one.
474 public void registerExtension() {
478 public void registerImplementation() {
479 implementationsCount++;
482 public void registerReference() {
486 public void setDistinctiveColor(final String distinctiveColor) {
487 distinctiveReferenceColor = distinctiveColor;