Updated copyright info
[javainspect.git] / src / main / java / eu / svjatoslav / inspector / java / structure / ClassDescriptor.java
old mode 100644 (file)
new mode 100755 (executable)
index eae630b..118994e
 /*
  * JavaInspect - Utility to visualize java software
- * Copyright (C) 2013, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
- * 
+ * Copyright (C) 2013-2020, 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;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.SortedSet;
-import java.util.TreeMap;
-import java.util.TreeSet;
+import java.util.*;
 
 /**
  * Describes single class instance
  */
-public class ClassDescriptor implements GraphElement {
+public class ClassDescriptor implements GraphElement, Comparable<ClassDescriptor> {
+
+    private static final int MAX_REFERECNES_COUNT = 10;
+    final List<ClassDescriptor> interfaces = new ArrayList<>();
+    private final Map<String, FieldDescriptor> nameToFieldMap = new TreeMap<>();
+    private final SortedSet<MethodDescriptor> methods = new TreeSet<>();
+    private final ClassGraph classGraph;
+    boolean isEnum;
+    boolean isInterface;
+    boolean isArray;
+    ClassDescriptor superClass;
+    private String fullyQualifiedName;
+    /**
+     * Incoming arrows will have this color.
+     */
+    private String distinctiveReferenceColor;
+    private String interfaceColor;
+    private String superClassColor;
+    private boolean isShown = true;
+    /**
+     * Amount of field and method references pointing to this class.
+     */
+    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 ClassGraph classGraph) {
+        this.classGraph = classGraph;
+    }
+
+    protected void analyzeClass(final Class<?> clazz) {
+
+        fullyQualifiedName = clazz.getName();
+
+        isArray = clazz.isArray();
+
+        if (isArray) {
+            final Class<?> componentType = clazz.getComponentType();
+            arrayComponent = getClassGraph().getOrCreateClassDescriptor(
+                    componentType);
+        }
+
+        // System.out.println("class: " + fullyQualifiedName);
+
+        isEnum = clazz.isEnum();
+
+        isInterface = clazz.isInterface();
+
+        if (!isVisible())
+            return;
+
+        try {
+            indexFields(clazz.getDeclaredFields());
+            indexFields(clazz.getFields());
+        } catch (NoClassDefFoundError error) {
+            // TODO: better logging of this error
+            System.out.println(error.toString());
+        }
+
+        indexMethods(clazz);
+
+        for (final Class interfaceClass : clazz.getInterfaces()) {
+            final ClassDescriptor interfaceClassDescriptor = getClassGraph()
+                    .getOrCreateClassDescriptor(interfaceClass);
+            interfaceClassDescriptor.registerImplementation();
+            interfaces.add(interfaceClassDescriptor);
+        }
+
+        superClass = getClassGraph().getOrCreateClassDescriptor(
+                clazz.getSuperclass());
+        if (superClass != null)
+            superClass.registerExtension();
+
+    }
+
+    protected boolean areReferencesShown() {
+        return referencesCount <= MAX_REFERECNES_COUNT;
+    }
+
+    private void enlistFieldReferences(final StringBuffer result) {
+        if (nameToFieldMap.isEmpty())
+            return;
+
+        result.append("\n");
+        result.append("    // field references to other classes\n");
+        nameToFieldMap.forEach((fieldName, field) -> result.append(field.getDot()));
+    }
+
+    private void enlistFields(final StringBuffer result) {
+        if (nameToFieldMap.isEmpty())
+            return;
+
+        result.append("\n");
+        result.append("    // fields:\n");
+
+        // enlist fields
+        for (final Map.Entry<String, FieldDescriptor> entry : nameToFieldMap
+                .entrySet())
+            result.append(entry.getValue().getEmbeddedDot());
+    }
+
+    private void enlistImplementedInterfaces(final StringBuffer result) {
+        if (interfaces.isEmpty())
+            return;
 
-       private static final int MAX_REFERECNES_COUNT = 10;
+        result.append("\n");
+        result.append("    // interfaces implemented by class: "
+                + fullyQualifiedName + "\n");
 
-       public final String fullyQualifiedName;
+        for (final ClassDescriptor interfaceDescriptor : interfaces) {
+            if (!interfaceDescriptor.isVisible())
+                continue;
 
-       Map<String, FieldDescriptor> nameToFieldMap = new TreeMap<String, FieldDescriptor>();
+            if (!interfaceDescriptor.areReferencesShown())
+                continue;
 
-       public SortedSet<MethodDescriptor> methods = new TreeSet<MethodDescriptor>();
+            result.append("    " + interfaceDescriptor.getGraphId() + " -> "
+                    + getGraphId() + "[style=\"dotted\", color=\""
+                    + interfaceDescriptor.getInterfaceColor()
+                    + "\", penwidth=10, dir=\"forward\"];\n");
+        }
+    }
 
-       /**
-        * Incoming arrows will have this color.
-        */
-       private String distinctiveReferenceColor;
+    private void enlistMethodReferences(final StringBuffer result) {
+        if (methods.isEmpty())
+            return;
+
+        result.append("\n");
+        result.append("    // method references to other classes\n");
+        for (final MethodDescriptor methodDescriptor : methods)
+            result.append(methodDescriptor.getDot());
+    }
+
+    private void enlistMethods(final StringBuffer result) {
+        if (methods.isEmpty())
+            return;
+
+        result.append("\n");
+        result.append("    // methods:\n");
+
+        // enlist methods
+        for (final MethodDescriptor methodDescriptor : methods)
+            result.append(methodDescriptor.getEmbeddedDot());
+    }
+
+    private void enlistSuperClass(final StringBuffer result) {
+        if (superClass == null)
+            return;
+
+        if (!superClass.isVisible())
+            return;
+
+        if (!superClass.areReferencesShown())
+            return;
+
+        result.append("\n");
+        result.append("    // super class for: " + fullyQualifiedName + "\n");
 
-       private String interfaceColor;
+        result.append("    " + superClass.getGraphId() + " -> " + getGraphId()
+                + "[ color=\"" + superClass.getSuperClassColor()
+                + "\", penwidth=10, dir=\"forward\"];\n");
+    }
 
-       private String superClassColor;
+    private void generateDotHeader(final StringBuffer result) {
+        result.append("\n");
+        result.append("// Class: " + fullyQualifiedName + "\n");
 
-       boolean isEnum;
+        result.append("    " + getGraphId() + "[label=<<TABLE "
+                + getBackgroundColor() + " BORDER=\"" + getBorderWidth()
+                + "\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n");
 
-       boolean isInterface;
+        result.append("\n");
+        result.append("    // class descriptor header\n");
+        result.append("    <TR><TD colspan=\"2\" PORT=\"f0\">"
+                + "<FONT POINT-SIZE=\"8.0\" >" + getPackageName()
+                + "</FONT><br/>");
 
-       boolean isArray;
+        final String parentClassesName = getParentClassesName();
+        if (parentClassesName.length() > 0)
+            result.append("<FONT POINT-SIZE=\"12.0\"><B>" + parentClassesName
+                    + "</B></FONT><br/>\n");
 
-       private boolean isShown = true;
+        result.append("<FONT POINT-SIZE=\"25.0\"><B>" + getClassName(false)
+                + "</B></FONT>" + "</TD></TR>\n");
+    }
 
-       private final ClassGraph classGraph;
+    private String getBackgroundColor() {
+        String bgColor = "";
 
-       List<ClassDescriptor> interfaces = new ArrayList<ClassDescriptor>();
+        if (isEnum)
+            bgColor = "bgcolor=\"navajowhite2\"";
 
-       ClassDescriptor superClass;
+        if (isInterface)
+            bgColor = "bgcolor=\"darkslategray1\"";
 
-       /**
-        * Amount of field and method references pointing to this class.
-        */
-       private int incomingReferencesCount = 0;
+        return bgColor;
+    }
 
-       private int extensionsCount = 0;
+    private String getBorderWidth() {
 
-       public ClassDescriptor(final Class<? extends Object> clazz,
-                       final ClassGraph dump) {
-               classGraph = dump;
+        if (!areReferencesShown())
+            return "4";
+        return "1";
+    }
 
-               fullyQualifiedName = clazz.getName();
-               dump.nameToClassMap.put(fullyQualifiedName, this);
+    protected ClassGraph getClassGraph() {
+        return classGraph;
+    }
 
-               isArray = clazz.isArray();
+    protected String getClassName(final boolean differentiateArray) {
+        // this is needed for nested classes
+        final String actualClassName = fullyQualifiedName.replace('$', '.');
 
-               if (isArray) {
-                       final Class<?> componentType = clazz.getComponentType();
-                       dump.addClass(componentType);
-               }
+        String result;
+        if (isArray) {
+            // for arrays use array component instead of array class name
+            result = arrayComponent.fullyQualifiedName;
+            if (result.contains(".")) {
+                final int i = result.lastIndexOf('.');
+                result = result.substring(i + 1);
+            }
+        } else {
+            final int i = actualClassName.lastIndexOf('.');
+            result = actualClassName.substring(i + 1);
+        }
 
-               // System.out.println("class: " + fullyQualifiedName);
+        if (differentiateArray)
+            if (isArray)
+                result += " []";
 
-               isEnum = clazz.isEnum();
+        // this is needed for nested classes
+        // result = result.replace('$', '.');
+        return result;
+    }
 
-               isInterface = clazz.isInterface();
+    protected String getColor() {
+        if (distinctiveReferenceColor == null)
+            distinctiveReferenceColor = Utils.getNextDarkColor();
 
-               if (!isVisible())
-                       return;
+        return distinctiveReferenceColor;
+    }
 
-               indexFields(clazz.getDeclaredFields());
-               indexFields(clazz.getFields());
+    @Override
+    public String getDot() {
+        if (!isVisible())
+            return "";
 
-               indexMethods(clazz);
+        if (isArray)
+            return "";
 
-               for (final Class interfaceClass : clazz.getInterfaces()) {
-                       final ClassDescriptor classDescriptor = dump
-                                       .addClass(interfaceClass);
-                       classDescriptor.registerExtension();
-                       interfaces.add(classDescriptor);
-               }
+        final StringBuffer result = new StringBuffer();
 
-               superClass = dump.addClass(clazz.getSuperclass());
-               if (superClass != null)
-                       superClass.registerExtension();
+        generateDotHeader(result);
 
-       }
+        enlistFields(result);
 
-       public boolean areReferencesShown() {
-               return incomingReferencesCount <= MAX_REFERECNES_COUNT;
-       }
+        enlistMethods(result);
 
-       public void enlistFieldReferences(final StringBuffer result) {
-               if (nameToFieldMap.isEmpty())
-                       return;
+        result.append("    </TABLE>>, shape=\"none\"];\n");
 
-               result.append("\n");
-               result.append("    // field references to other classes\n");
-               for (final Map.Entry<String, FieldDescriptor> entry : nameToFieldMap
-                               .entrySet())
-                       result.append(entry.getValue().getDot());
-       }
+        enlistFieldReferences(result);
 
-       public void enlistFields(final StringBuffer result) {
-               if (nameToFieldMap.isEmpty())
-                       return;
+        enlistMethodReferences(result);
 
-               result.append("\n");
-               result.append("    // fields:\n");
+        enlistImplementedInterfaces(result);
 
-               // enlist fields
-               for (final Map.Entry<String, FieldDescriptor> entry : nameToFieldMap
-                               .entrySet())
-                       result.append(entry.getValue().getEmbeddedDot());
-       }
+        enlistSuperClass(result);
 
-       public void enlistImplementedInterfaces(final StringBuffer result) {
-               if (interfaces.isEmpty())
-                       return;
+        return result.toString();
+    }
 
-               result.append("\n");
-               result.append("    // interfaces implemented by class: "
-                               + fullyQualifiedName + "\n");
+    @Override
+    public String getEmbeddedDot() {
+        return null;
+    }
 
-               for (final ClassDescriptor interfaceDescriptor : interfaces) {
-                       if (!interfaceDescriptor.isVisible())
-                               continue;
+    /**
+     * Returns field with given name (case is ignored). Or <code>null</code> if
+     * field is not found.
+     *
+     * @param fieldToSearch field name (case is ignored)
+     * @return field matching given name
+     */
+    protected FieldDescriptor getFieldIgnoreCase(final String fieldToSearch) {
 
-                       result.append("    " + interfaceDescriptor.getGraphId() + " -> "
-                                       + getGraphId() + "[style=\"dotted, tapered\", color=\""
-                                       + interfaceDescriptor.getInterfaceColor()
-                                       + "\", penwidth=20, dir=\"forward\"];\n");
-               }
-       }
+        for (final String fieldName : nameToFieldMap.keySet())
+            if (fieldToSearch.equalsIgnoreCase(fieldName))
+                return nameToFieldMap.get(fieldName);
 
-       public void enlistMethodReferences(final StringBuffer result) {
-               if (methods.isEmpty())
-                       return;
+        return null;
+    }
 
-               result.append("\n");
-               result.append("    // method references to other classes\n");
-               for (final MethodDescriptor methodDescriptor : methods)
-                       result.append(methodDescriptor.getDot());
-       }
+    protected String getFullyQualifiedName() {
+        return fullyQualifiedName;
+    }
 
-       public void enlistMethods(final StringBuffer result) {
-               if (methods.isEmpty())
-                       return;
+    @Override
+    public String getGraphId() {
 
-               result.append("\n");
-               result.append("    // methods:\n");
+        return "class_"
+                + fullyQualifiedName
+                .replace('.', '_')
+                .replace(";", "")
+                .replace("[[", "")
+                .replace("[L", "")
+                .replace("[[L", "") // array of arrays
+                .replace("[[[L", "") // array of arrays of arrays
+                .replace('$', '_');
+    }
 
-               // enlist methods
-               for (final MethodDescriptor methodDescriptor : methods)
-                       result.append(methodDescriptor.getEmbeddedDot());
-       }
+    private String getInterfaceColor() {
+        if (interfaceColor == null)
+            interfaceColor = Utils.getNextDarkColor();
 
-       public void enlistSuperClass(final StringBuffer result) {
-               if (superClass == null)
-                       return;
+        return interfaceColor;
+    }
 
-               if (!superClass.isVisible())
-                       return;
+    private FieldDescriptor getOrCreateFieldDescriptor(final Field field) {
 
-               result.append("\n");
-               result.append("    // super class for: " + fullyQualifiedName + "\n");
+        final String fieldName = field.getName();
 
-               result.append("    " + superClass.getGraphId() + " -> " + getGraphId()
-                               + "[style=\"tapered\", color=\""
-                               + superClass.getSuperClassColor()
-                               + "\", penwidth=10, dir=\"forward\"];\n");
-       }
+        if (nameToFieldMap.containsKey(fieldName))
+            return nameToFieldMap.get(fieldName);
 
-       public void generateDotHeader(final StringBuffer result) {
-               result.append("\n");
-               result.append("// Class: " + fullyQualifiedName + "\n");
+        final FieldDescriptor newFieldDescriptor = new FieldDescriptor(this);
+        nameToFieldMap.put(fieldName, newFieldDescriptor);
 
-               result.append("    " + getGraphId() + "[label=<<TABLE "
-                               + getBackgroundColor() + " BORDER=\"" + getBorderWidth()
-                               + "\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n");
+        newFieldDescriptor.analyzeField(field);
 
-               result.append("\n");
-               result.append("    // class descriptor header\n");
-               result.append("    <TR><TD colspan=\"2\" PORT=\"f0\">"
-                               + "<FONT POINT-SIZE=\"8.0\" >" + getPackageName()
-                               + "</FONT><br/>");
+        return newFieldDescriptor;
+    }
 
-               final String parentClassesName = getParentClassesName();
-               if (parentClassesName.length() > 0)
-                       result.append("<FONT POINT-SIZE=\"12.0\"><B>" + parentClassesName
-                                       + "</B></FONT><br/>\n");
+    private int getOutgoingReferencesCount() {
+        int result = 0;
 
-               result.append("<FONT POINT-SIZE=\"25.0\"><B>" + getClassName(false)
-                               + "</B></FONT>" + "</TD></TR>\n");
-       }
+        // count method references
+        for (final MethodDescriptor methodDescriptor : methods)
+            result += methodDescriptor.getOutsideVisibleReferencesCount();
 
-       public List<FieldDescriptor> getAllFields() {
-               final List<FieldDescriptor> result = new ArrayList<FieldDescriptor>();
+        // count field references
+        for (final FieldDescriptor fieldDescriptor : nameToFieldMap.values())
+            result += fieldDescriptor.getOutsideVisibleReferencesCount();
 
-               for (final Map.Entry<String, FieldDescriptor> entry : nameToFieldMap
-                               .entrySet())
-                       result.add(entry.getValue());
+        // count implemented interfaces
+        for (final ClassDescriptor classDescriptor : interfaces)
+            if (classDescriptor.isVisible())
+                result++;
 
-               return result;
-       }
+        // count superclass
+        if (superClass != null)
+            if (superClass.isVisible())
+                result++;
 
-       public String getBackgroundColor() {
-               String bgColor = "";
+        return result;
+    }
 
-               if (isEnum)
-                       bgColor = "bgcolor=\"navajowhite2\"";
+    private String getPackageName() {
 
-               if (isInterface)
-                       bgColor = "bgcolor=\"darkslategray1\"";
+        final int i = fullyQualifiedName.lastIndexOf('.');
 
-               return bgColor;
-       }
+        if (i == -1)
+            return "";
 
-       public String getBorderWidth() {
+        return fullyQualifiedName.substring(0, i).replace("[L", "");
+    }
 
-               if (!areReferencesShown())
-                       return "4";
-               return "1";
-       }
+    private String getParentClassesName() {
+        int i = fullyQualifiedName.lastIndexOf('.');
+        final String fullClassName = fullyQualifiedName.substring(i + 1);
 
-       public String getClassName(final boolean differentiateArray) {
-               // this is needed for nested classes
-               final String actualClassName = fullyQualifiedName.replace('$', '.');
+        i = fullClassName.lastIndexOf('$');
+        if (i == -1)
+            return "";
+        final String parentClassesName = fullClassName.substring(0, i);
+        return parentClassesName.replace('$', '.');
+    }
 
-               final int i = actualClassName.lastIndexOf('.');
+    private String getSuperClassColor() {
+        if (superClassColor == null)
+            superClassColor = Utils.getNextLightColor();
 
-               String result = actualClassName.substring(i + 1);
+        return superClassColor;
+    }
 
-               if (isArray)
-                       result = result.substring(0, result.length() - 1);
+    /**
+     * Checks if class has field with given name (case is ignored). Returns
+     * <code>true</code> if such field is found.
+     *
+     * @param fieldToSearch field to search for (case is ignored)
+     * @return <code>true</code> if field is found.
+     */
+    protected boolean hasFieldIgnoreCase(final String fieldToSearch) {
 
-               if (differentiateArray)
-                       if (isArray)
-                               result += " []";
+        for (final String fieldName : nameToFieldMap.keySet())
+            if (fieldToSearch.equalsIgnoreCase(fieldName))
+                return true;
 
-               // this is needed for nested classes
-               // result = result.replace('$', '.');
-               return result;
-       }
+        return false;
+    }
 
-       public String getColor() {
-               if (getDistinctiveColor() == null)
-                       setDistinctiveColor(Utils.getNextDarkColor());
+    private void hide() {
+        isShown = false;
+    }
 
-               return getDistinctiveColor();
-       }
+    protected void hideClassIfNoReferences() {
+        if (!isVisible())
+            return;
 
-       public String getDistinctiveColor() {
-               return distinctiveReferenceColor;
-       }
+        final int totalReferencesCount = getOutgoingReferencesCount()
+                + referencesCount + extensionsCount + implementationsCount;
 
-       @Override
-       public String getDot() {
-               if (!isVisible())
-                       return "";
+        if (totalReferencesCount == 0) {
+            hide();
+            return;
+        }
 
-               if (isArray)
-                       return "";
+    }
 
-               final StringBuffer result = new StringBuffer();
+    private void indexFields(final Field[] fields) {
+        for (final Field field : fields)
+            getOrCreateFieldDescriptor(field);
+    }
 
-               generateDotHeader(result);
+    private void indexMethods(final Class<?> clazz) {
+        for (final Method method : clazz.getMethods()) {
+            final MethodDescriptor methodDescriptor = new MethodDescriptor(
+                    this, method.getName());
 
-               enlistFields(result);
+            methods.add(methodDescriptor);
 
-               enlistMethods(result);
+            methodDescriptor.analyze(method);
+        }
 
-               result.append("    </TABLE>>, shape=\"none\"];\n");
+    }
 
-               enlistFieldReferences(result);
+    @Override
+    public boolean isVisible() {
 
-               enlistMethodReferences(result);
+        if (Utils.isSystemDataType(fullyQualifiedName))
+            return false;
 
-               enlistImplementedInterfaces(result);
+        if (Utils.isSystemPackage(fullyQualifiedName))
+            return false;
 
-               enlistSuperClass(result);
+        if (!getClassGraph().isClassShown(fullyQualifiedName))
+            return false;
 
-               return result.toString();
-       }
+        if (isArray)
+            if (arrayComponent != null)
+                if (Utils.isSystemDataType(arrayComponent.fullyQualifiedName))
+                    // 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;
 
-       @Override
-       public String getEmbeddedDot() {
-               return null;
-       }
+        return isShown;
+    }
 
-       @Override
-       public String getGraphId() {
-               final String result = "class_"
-                               + fullyQualifiedName.replace('.', '_').replace(";", "")
-                                               .replace("[L", "").replace('$', '_');
-               return result;
-       }
+    /**
+     * Register event when another class is extending this one.
+     */
+    protected void registerExtension() {
+        extensionsCount++;
+    }
 
-       public String getInterfaceColor() {
-               if (interfaceColor == null)
-                       interfaceColor = Utils.getNextLightColor();
+    protected void registerImplementation() {
+        implementationsCount++;
+    }
 
-               return interfaceColor;
-       }
+    protected void registerReference() {
+        referencesCount++;
+    }
 
-       private int getOutgoingReferencesCount() {
-               int result = 0;
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof ClassDescriptor)) return false;
 
-               // count method references
-               for (final MethodDescriptor methodDescriptor : methods)
-                       result += methodDescriptor.getOutsideVisibleReferencesCount();
+        ClassDescriptor that = (ClassDescriptor) o;
 
-               // count field references
-               for (final FieldDescriptor fieldDescriptor : nameToFieldMap.values())
-                       result += fieldDescriptor.getOutsideVisibleReferencesCount();
+        return getFullyQualifiedName().equals(that.getFullyQualifiedName());
 
-               // count implemented interfaces
-               for (final ClassDescriptor classDescriptor : interfaces)
-                       if (classDescriptor.isVisible())
-                               result++;
+    }
 
-               // count superclass
-               if (superClass != null)
-                       if (superClass.isVisible())
-                               result++;
+    @Override
+    public int hashCode() {
+        return getFullyQualifiedName().hashCode();
+    }
 
-               return result;
-       }
-
-       public String getPackageName() {
-
-               final int i = fullyQualifiedName.lastIndexOf('.');
-
-               if (i == -1)
-                       return "";
-
-               return fullyQualifiedName.substring(0, i).replace("[L", "");
-       }
-
-       // public String getReadableName() {
-       //
-       // // do not print full class name for well known system classes
-       // final String packageName = getPackageName();
-       //
-       // if (packageName.equals("java.util"))
-       // return getClassName();
-       //
-       // if (packageName.equals("java.lang"))
-       // return getClassName();
-       //
-       // return fullyQualifiedName;
-       // }
-
-       public String getParentClassesName() {
-               int i = fullyQualifiedName.lastIndexOf('.');
-               final String fullClassName = fullyQualifiedName.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;
-       }
-
-       public void hide() {
-               isShown = false;
-       }
-
-       public void hideClassIfNoReferences() {
-               if (!isVisible())
-                       return;
-
-               final int totalReferencesCount = getOutgoingReferencesCount()
-                               + incomingReferencesCount + extensionsCount;
-
-               if (totalReferencesCount == 0) {
-                       hide();
-                       return;
-               }
-
-               return;
-       }
-
-       public void indexFields(final Field[] fields) {
-               for (final Field field : fields) {
-                       if (nameToFieldMap.containsKey(field.getName()))
-                               continue;
-
-                       final FieldDescriptor fieldDescriptor = new FieldDescriptor(field,
-                                       this, classGraph);
-
-               }
-       }
-
-       private void indexMethods(final Class<? extends Object> clazz) {
-               final Method[] methods = clazz.getMethods();
-
-               for (final Method method : methods)
-                       new MethodDescriptor(method, this, classGraph);
-
-       }
-
-       @Override
-       public boolean isVisible() {
-
-               if (Utils.isSystemDataType(fullyQualifiedName))
-                       return false;
-
-               if (Utils.isSystemPackage(fullyQualifiedName))
-                       return false;
-
-               if (!classGraph.getFilter().isClassShown(fullyQualifiedName))
-                       return false;
-
-               return isShown;
-       }
-
-       /**
-        * Register event when another class is extending this one, or is
-        * implementing interface declared by this class.
-        */
-       public void registerExtension() {
-               extensionsCount++;
-       }
-
-       public void registerReference() {
-               incomingReferencesCount++;
-       }
-
-       public void setDistinctiveColor(final String distinctiveColor) {
-               distinctiveReferenceColor = distinctiveColor;
-       }
+    @Override
+    public int compareTo(ClassDescriptor o) {
+        return fullyQualifiedName.compareTo(o.fullyQualifiedName);
+    }
 }