/*
* JavaInspect - Utility to visualize java software
- * Copyright (C) 2013, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
- *
+ * 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 2 of the GNU General Public License
- * as published by the Free Software Foundation.
+ * modify it under the terms of version 3 of the GNU Lesser General Public License
+ * or later as published by the Free Software Foundation.
*/
package eu.svjatoslav.inspector.java.structure;
private static final int MAX_REFERECNES_COUNT = 10;
- public final String fullyQualifiedName;
+ public final String classFullyQualifiedName;
Map<String, FieldDescriptor> nameToFieldMap = new TreeMap<String, FieldDescriptor>();
/**
* Amount of field and method references pointing to this class.
*/
- private int incomingReferencesCount = 0;
+ private int referencesCount = 0;
+
+ // for interface, counts amount of found implementations
+ private int implementationsCount = 0;
+
+ // 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;
- fullyQualifiedName = clazz.getName();
- dump.nameToClassMap.put(fullyQualifiedName, this);
+ classFullyQualifiedName = clazz.getName();
+
+ 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())
- interfaces.add(dump.addClass(interfaceClass));
+ for (final Class interfaceClass : clazz.getInterfaces()) {
+ final ClassDescriptor classDescriptor = classGraph
+ .addClass(interfaceClass);
+ classDescriptor.registerImplementation();
+ interfaces.add(classDescriptor);
+ }
+
+ superClass = classGraph.addClass(clazz.getSuperclass());
+ if (superClass != null)
+ superClass.registerExtension();
- superClass = dump.addClass(clazz.getSuperclass());
}
public boolean areReferencesShown() {
- return incomingReferencesCount <= MAX_REFERECNES_COUNT;
+ return referencesCount <= MAX_REFERECNES_COUNT;
}
public void enlistFieldReferences(final StringBuffer result) {
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)
return null;
}
+ /**
+ * Returns field with given name (case is ignored). Or <code>null</code> if
+ * field is not found.
+ */
+ public FieldDescriptor getFieldIgnoreCase(final String fieldToSearch) {
+
+ for (final String fieldName : nameToFieldMap.keySet())
+ if (fieldToSearch.equalsIgnoreCase(fieldName))
+ return nameToFieldMap.get(fieldName);
+
+ return null;
+ }
+
@Override
public String getGraphId() {
final String result = "class_"
- + fullyQualifiedName.replace('.', '_').replace(";", "")
+ + classFullyQualifiedName.replace('.', '_').replace(";", "")
.replace("[L", "").replace('$', '_');
return result;
}
return interfaceColor;
}
- public String getPackageName() {
+ private int getOutgoingReferencesCount() {
+ int result = 0;
- final int i = fullyQualifiedName.lastIndexOf('.');
+ // count method references
+ for (final MethodDescriptor methodDescriptor : methods)
+ result += methodDescriptor.getOutsideVisibleReferencesCount();
- if (i == -1)
- return "";
+ // count field references
+ for (final FieldDescriptor fieldDescriptor : nameToFieldMap.values())
+ result += fieldDescriptor.getOutsideVisibleReferencesCount();
- return fullyQualifiedName.substring(0, i).replace("[L", "");
- }
+ // count implemented interfaces
+ for (final ClassDescriptor classDescriptor : interfaces)
+ if (classDescriptor.isVisible())
+ result++;
- public String getParentClassesName() {
- int i = fullyQualifiedName.lastIndexOf('.');
- final String fullClassName = fullyQualifiedName.substring(i + 1);
+ // count superclass
+ if (superClass != null)
+ if (superClass.isVisible())
+ result++;
- i = fullClassName.lastIndexOf('$');
- if (i == -1)
- return "";
- final String parentClassesName = fullClassName.substring(0, i);
- return parentClassesName.replace('$', '.');
+ return result;
}
// public String getReadableName() {
// return fullyQualifiedName;
// }
+ public String getPackageName() {
+
+ final int i = classFullyQualifiedName.lastIndexOf('.');
+
+ if (i == -1)
+ return "";
+
+ return classFullyQualifiedName.substring(0, i).replace("[L", "");
+ }
+
+ public String getParentClassesName() {
+ int i = classFullyQualifiedName.lastIndexOf('.');
+ final String fullClassName = classFullyQualifiedName.substring(i + 1);
+
+ i = fullClassName.lastIndexOf('$');
+ if (i == -1)
+ return "";
+ final String parentClassesName = fullClassName.substring(0, i);
+ return parentClassesName.replace('$', '.');
+ }
+
public String getSuperClassColor() {
if (superClassColor == null)
superClassColor = Utils.getNextLightColor();
return superClassColor;
}
+ /**
+ * Checks if class has field with given name (case is ignored). Returns
+ * <code>true</code> if such field is found.
+ */
+ public boolean hasFieldIgnoreCase(final String fieldToSearch) {
+
+ for (final String fieldName : nameToFieldMap.keySet())
+ if (fieldToSearch.equalsIgnoreCase(fieldName))
+ return true;
+
+ return false;
+ }
+
public void hide() {
isShown = false;
}
- public boolean hideClassIfNoReferences() {
+ public void hideClassIfNoReferences() {
if (!isVisible())
- return false;
-
- int outgoingVisibleReferencesCount = 0;
-
- for (final MethodDescriptor methodDescriptor : methods)
- outgoingVisibleReferencesCount += methodDescriptor
- .getOutsideVisibleReferencesCount();
-
- for (final FieldDescriptor fieldDescriptor : nameToFieldMap.values())
- outgoingVisibleReferencesCount += fieldDescriptor
- .getOutsideVisibleReferencesCount();
+ return;
- final int totalReferencesCount = outgoingVisibleReferencesCount
- + incomingReferencesCount;
+ final int totalReferencesCount = getOutgoingReferencesCount()
+ + referencesCount + extensionsCount + implementationsCount;
if (totalReferencesCount == 0) {
hide();
- return true;
+ return;
}
- return false;
+ return;
}
public void indexFields(final Field[] fields) {
@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;
}
+ /**
+ * Register event when another class is extending this one.
+ */
+ public void registerExtension() {
+ extensionsCount++;
+ }
+
+ public void registerImplementation() {
+ implementationsCount++;
+ }
+
public void registerReference() {
- incomingReferencesCount++;
+ referencesCount++;
}
public void setDistinctiveColor(final String distinctiveColor) {