/*
* JavaInspect - Utility to visualize java software
* Copyright (C) 2013-2014, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
- *
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 3 of the GNU Lesser General Public License
* or later as published by the Free Software Foundation.
private static final int MAX_REFERECNES_COUNT = 10;
- public final String fullyQualifiedName;
+ public final String classFullyQualifiedName;
Map<String, FieldDescriptor> nameToFieldMap = new TreeMap<String, FieldDescriptor>();
// counts amount of times this class is extended
private int extensionsCount = 0;
+ private ClassDescriptor arrayComponent;
+
public ClassDescriptor(final Class<? extends Object> clazz,
- final ClassGraph dump) {
- classGraph = dump;
+ final ClassGraph classGraph) {
+ this.classGraph = classGraph;
+
+ classFullyQualifiedName = clazz.getName();
- fullyQualifiedName = clazz.getName();
- dump.nameToClassMap.put(fullyQualifiedName, this);
+ classGraph.registerClass(classFullyQualifiedName, this);
isArray = clazz.isArray();
if (isArray) {
final Class<?> componentType = clazz.getComponentType();
- dump.addClass(componentType);
+ arrayComponent = classGraph.addClass(componentType);
}
// System.out.println("class: " + fullyQualifiedName);
indexMethods(clazz);
for (final Class interfaceClass : clazz.getInterfaces()) {
- final ClassDescriptor classDescriptor = dump
+ final ClassDescriptor classDescriptor = classGraph
.addClass(interfaceClass);
classDescriptor.registerImplementation();
interfaces.add(classDescriptor);
}
- superClass = dump.addClass(clazz.getSuperclass());
+ superClass = classGraph.addClass(clazz.getSuperclass());
if (superClass != null)
superClass.registerExtension();
result.append("\n");
result.append(" // interfaces implemented by class: "
- + fullyQualifiedName + "\n");
+ + classFullyQualifiedName + "\n");
for (final ClassDescriptor interfaceDescriptor : interfaces) {
if (!interfaceDescriptor.isVisible())
return;
result.append("\n");
- result.append(" // super class for: " + fullyQualifiedName + "\n");
+ result.append(" // super class for: " + classFullyQualifiedName
+ + "\n");
result.append(" " + superClass.getGraphId() + " -> " + getGraphId()
+ "[style=\"tapered\", color=\""
public void generateDotHeader(final StringBuffer result) {
result.append("\n");
- result.append("// Class: " + fullyQualifiedName + "\n");
+ result.append("// Class: " + classFullyQualifiedName + "\n");
result.append(" " + getGraphId() + "[label=<<TABLE "
+ getBackgroundColor() + " BORDER=\"" + getBorderWidth()
public String getClassName(final boolean differentiateArray) {
// this is needed for nested classes
- final String actualClassName = fullyQualifiedName.replace('$', '.');
-
- final int i = actualClassName.lastIndexOf('.');
+ final String actualClassName = classFullyQualifiedName
+ .replace('$', '.');
- String result = actualClassName.substring(i + 1);
-
- if (isArray)
- result = result.substring(0, result.length() - 1);
+ String result;
+ if (isArray) {
+ // for arrays use array component instead of array class name
+ result = arrayComponent.classFullyQualifiedName;
+ if (result.contains(".")) {
+ final int i = result.lastIndexOf('.');
+ result = result.substring(i + 1);
+ }
+ } else {
+ final int i = actualClassName.lastIndexOf('.');
+ result = actualClassName.substring(i + 1);
+ }
if (differentiateArray)
if (isArray)
@Override
public String getGraphId() {
final String result = "class_"
- + fullyQualifiedName.replace('.', '_').replace(";", "")
- .replace("[L", "").replace('$', '_');
+ + classFullyQualifiedName.replace('.', '_').replace(";", "")
+ .replace("[L", "").replace('$', '_');
return result;
}
public String getPackageName() {
- final int i = fullyQualifiedName.lastIndexOf('.');
+ final int i = classFullyQualifiedName.lastIndexOf('.');
if (i == -1)
return "";
- return fullyQualifiedName.substring(0, i).replace("[L", "");
+ return classFullyQualifiedName.substring(0, i).replace("[L", "");
}
public String getParentClassesName() {
- int i = fullyQualifiedName.lastIndexOf('.');
- final String fullClassName = fullyQualifiedName.substring(i + 1);
+ int i = classFullyQualifiedName.lastIndexOf('.');
+ final String fullClassName = classFullyQualifiedName.substring(i + 1);
i = fullClassName.lastIndexOf('$');
if (i == -1)
@Override
public boolean isVisible() {
- if (Utils.isSystemDataType(fullyQualifiedName))
+ if (Utils.isSystemDataType(classFullyQualifiedName))
return false;
- if (Utils.isSystemPackage(fullyQualifiedName))
+ if (Utils.isSystemPackage(classFullyQualifiedName))
return false;
- if (!classGraph.getFilter().isClassShown(fullyQualifiedName))
+ if (!classGraph.getFilter().isClassShown(classFullyQualifiedName))
return false;
+ if (isArray)
+ if (arrayComponent != null)
+ if (Utils
+ .isSystemDataType(arrayComponent.classFullyQualifiedName))
+ // Do not show references to primitive data types in arrays.
+ // That is: there is no point to show reference to byte when
+ // we have class with byte array field.
+ return false;
+
return isShown;
}
/**
* Maps class fully qualified names to class descriptors.
*/
- Map<String, ClassDescriptor> nameToClassMap = new HashMap<String, ClassDescriptor>();
+ private final Map<String, ClassDescriptor> fullyQualifiedNameToClassMap = new HashMap<String, ClassDescriptor>();
private Filter filter = new Filter();
final String className = clazz.getName();
- if (nameToClassMap.containsKey(className))
- return nameToClassMap.get(className);
+ if (fullyQualifiedNameToClassMap.containsKey(className))
+ return fullyQualifiedNameToClassMap.get(className);
return new ClassDescriptor(clazz, this);
}
// execute GraphViz to visualize graph
try {
Runtime.getRuntime()
- .exec(new String[] { "dot", "-Tpng", dotFilePath, "-o",
- imageFilePath }).waitFor();
+ .exec(new String[] { "dot", "-Tpng", dotFilePath, "-o",
+ imageFilePath }).waitFor();
} catch (final InterruptedException e) {
} finally {
}
result.append("digraph Java {\n");
result.append("graph [rankdir=LR, overlap = false, concentrate=true];\n");
- for (final Map.Entry<String, ClassDescriptor> entry : nameToClassMap
+ for (final Map.Entry<String, ClassDescriptor> entry : fullyQualifiedNameToClassMap
.entrySet())
result.append(entry.getValue().getDot());
*/
public void hideOrphanedClasses() {
- for (final ClassDescriptor classDescriptor : nameToClassMap.values())
+ for (final ClassDescriptor classDescriptor : fullyQualifiedNameToClassMap
+ .values())
classDescriptor.hideClassIfNoReferences();
}
+ public void registerClass(final String classFullyQualifiedName,
+ final ClassDescriptor classDescriptor) {
+ fullyQualifiedNameToClassMap.put(classFullyQualifiedName,
+ classDescriptor);
+ }
+
public void setFilter(final Filter filter) {
this.filter = filter;
}
List<ClassDescriptor> typeArguments = new ArrayList<ClassDescriptor>();
public FieldDescriptor(final Field field, final ClassDescriptor parent,
- final ClassGraph dump) {
+ final ClassGraph classGraph) {
parentClass = parent;
if (!field.getDeclaringClass().getName()
- .equals(parent.fullyQualifiedName))
+ .equals(parent.classFullyQualifiedName))
// if field is inherited, do not index it
return;
parent.nameToFieldMap.put(field.getName(), this);
name = field.getName();
- type = dump.addClass(field.getType());
+ type = classGraph.addClass(field.getType());
type.registerReference();
final Type genericType = field.getGenericType();
for (final Type t : pt.getActualTypeArguments())
if (t instanceof Class) {
final Class cl = (Class) t;
- final ClassDescriptor genericTypeDescriptor = dump
+ final ClassDescriptor genericTypeDescriptor = classGraph
.addClass(cl);
genericTypeDescriptor.registerReference();
typeArguments.add(genericTypeDescriptor);
* This class corresponds to single method within a java class.
*/
- public String name;
+ public String methodName;
public ClassDescriptor returnType;
private final ClassDescriptor parentClass;
parentClass = parent;
- name = method.getName();
+ methodName = method.getName();
if (!method.getDeclaringClass().getName()
- .equals(parent.fullyQualifiedName))
+ .equals(parent.classFullyQualifiedName))
// do not index inherited methods
return;
@Override
public int compareTo(final MethodDescriptor o) {
- final int nameComparisonResult = name.compareTo(o.name);
+ final int nameComparisonResult = methodName.compareTo(o.methodName);
if (nameComparisonResult != 0)
return nameComparisonResult;
if (classDescriptor.isVisible())
if (classDescriptor.areReferencesShown())
result.append(" " + getGraphId() + " -> "
- + classDescriptor.getGraphId() + "[label=\"" + name
+ + classDescriptor.getGraphId() + "[label=\"" + methodName
+ "\", color=\"" + classDescriptor.getColor()
+ "\", style=\"dotted, bold\"];\n");
// main type
if (returnType.areReferencesShown())
result.append(" " + getGraphId() + " -> "
- + returnType.getGraphId() + "[label=\"" + name + "\","
+ + returnType.getGraphId() + "[label=\"" + methodName + "\","
+ " color=\"" + returnType.getColor()
+ "\", style=\"dotted, bold\"];\n");
final StringBuffer result = new StringBuffer();
- result.append(" // " + name + "\n");
+ result.append(" // " + methodName + "\n");
result.append(" <TR><td ALIGN=\"right\">"
+ "<FONT POINT-SIZE=\"8.0\">" + returnType.getClassName(true)
@Override
public String getGraphId() {
- return parentClass.getGraphId() + ":" + name;
+ return parentClass.getGraphId() + ":" + methodName;
}
public String getMethodLabel() {
- return name;
+ return methodName;
}
public int getOutsideVisibleReferencesCount() {
public boolean isVisible() {
// hide common object methods
- if (Utils.isCommonObjectMethod(name))
+ if (Utils.isCommonObjectMethod(methodName))
return false;
// hide common Enumeration methods
- if (parentClass.isEnum && Utils.isEnumMethod(name))
+ if (parentClass.isEnum && Utils.isEnumMethod(methodName))
return false;
// hide get/set methods for the field of the same name
- if (name.startsWith("get") || name.startsWith("set"))
- if (parentClass.hasFieldIgnoreCase(name.substring(3)))
+ if (methodName.startsWith("get") || methodName.startsWith("set"))
+ if (parentClass.hasFieldIgnoreCase(methodName.substring(3)))
return false;
// hide is methods for the boolean field of the same name
- if (name.startsWith("is")) {
- final FieldDescriptor field = parentClass.getFieldIgnoreCase(name
+ if (methodName.startsWith("is")) {
+ final FieldDescriptor field = parentClass.getFieldIgnoreCase(methodName
.substring(2));
if (field != null)
- if ("boolean".equals(field.getType().fullyQualifiedName))
+ if ("boolean".equals(field.getType().classFullyQualifiedName))
return false;
}