Fixed null pointer exception
[javainspect.git] / src / main / java / eu / svjatoslav / inspector / java / structure / MethodDescriptor.java
1 /*
2  * JavaInspect - Utility to visualize java software
3  * Copyright (C) 2013-2015, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of version 3 of the GNU Lesser General Public License
7  * or later as published by the Free Software Foundation.
8  */
9
10 package eu.svjatoslav.inspector.java.structure;
11
12 import java.lang.reflect.Method;
13 import java.lang.reflect.ParameterizedType;
14 import java.lang.reflect.Type;
15 import java.util.ArrayList;
16 import java.util.List;
17
18 /**
19  * This class corresponds to single method within a java class.
20  */
21 public class MethodDescriptor implements GraphElement,
22         Comparable<MethodDescriptor> {
23
24     private final String methodName;
25     private final ClassDescriptor parentClass;
26     private final List<ClassDescriptor> argumentTypes = new ArrayList<ClassDescriptor>();
27     private ClassDescriptor returnType;
28     private boolean isInherited;
29
30     public MethodDescriptor(final ClassDescriptor parent,
31                             final String methodName) {
32         parentClass = parent;
33         this.methodName = methodName;
34     }
35
36     public void analyze(final Method method) {
37
38         if (!method.getDeclaringClass().getName()
39                 .equals(parentClass.getFullyQualifiedName()))
40             isInherited = true;
41
42         returnType = parentClass.getClassGraph().getOrCreateClassDescriptor(
43                 method.getReturnType());
44         returnType.registerReference();
45
46         final Type genericType = method.getGenericReturnType();
47         if (genericType instanceof ParameterizedType) {
48             final ParameterizedType pt = (ParameterizedType) genericType;
49             for (final Type t : pt.getActualTypeArguments())
50                 if (t instanceof Class) {
51                     final Class cl = (Class) t;
52                     final ClassDescriptor classDescriptor = parentClass
53                             .getClassGraph().getOrCreateClassDescriptor(cl);
54                     classDescriptor.registerReference();
55                     argumentTypes.add(classDescriptor);
56                 }
57
58         }
59     }
60
61     @Override
62     public boolean equals(Object o) {
63         if (this == o) return true;
64         if (!(o instanceof MethodDescriptor)) return false;
65
66         MethodDescriptor that = (MethodDescriptor) o;
67
68         if (methodName != null ? !methodName.equals(that.methodName) : that.methodName != null) return false;
69         if (parentClass != null ? !parentClass.equals(that.parentClass) : that.parentClass != null) return false;
70         return argumentTypes != null ? argumentTypes.equals(that.argumentTypes) : that.argumentTypes == null;
71
72     }
73
74
75     @Override
76     public int hashCode() {
77         int result = methodName != null ? methodName.hashCode() : 0;
78         result = 31 * result + (parentClass != null ? parentClass.hashCode() : 0);
79         result = 31 * result + (argumentTypes != null ? argumentTypes.hashCode() : 0);
80         return result;
81     }
82
83     @Override
84     public String getDot() {
85
86         if (!isVisible())
87             return "";
88
89         final StringBuffer result = new StringBuffer();
90
91         // describe associated types
92         for (final ClassDescriptor classDescriptor : argumentTypes)
93             if (classDescriptor.isVisible())
94                 if (classDescriptor.areReferencesShown())
95                     result.append("    " + getGraphId() + " -> "
96                             + classDescriptor.getGraphId() + "[label=\""
97                             + methodName + "\", color=\""
98                             + classDescriptor.getColor()
99                             + "\", style=\"dotted, bold\"];\n");
100
101         if (!returnType.isVisible())
102             return result.toString();
103
104         // main type
105         if (returnType.areReferencesShown())
106             result.append("    " + getGraphId() + " -> "
107                     + returnType.getGraphId() + "[label=\"" + methodName
108                     + "\"," + " color=\"" + returnType.getColor()
109                     + "\", style=\"dotted, bold\"];\n");
110
111         return result.toString();
112     }
113
114     @Override
115     public String getEmbeddedDot() {
116         if (!isVisible())
117             return "";
118
119         final StringBuffer result = new StringBuffer();
120
121         result.append("        // " + methodName + "\n");
122
123         result.append("        <TR><td ALIGN=\"right\">"
124                 + "<FONT POINT-SIZE=\"8.0\">" + returnType.getClassName(true)
125                 + "</FONT>" + "</td><TD PORT=\"" + getMethodLabel()
126                 + "\" ALIGN=\"left\"><FONT COLOR =\"red\" POINT-SIZE=\"11.0\">"
127                 + getMethodLabel() + "</FONT></TD></TR>\n");
128
129         return result.toString();
130     }
131
132     @Override
133     public String getGraphId() {
134         return parentClass.getGraphId() + ":" + methodName;
135     }
136
137     private String getMethodLabel() {
138         return methodName;
139     }
140
141     protected int getOutsideVisibleReferencesCount() {
142         int result = 0;
143
144         if (returnType != null)
145             if (returnType.isVisible())
146                 result++;
147
148         for (final ClassDescriptor classDescriptor : argumentTypes)
149             if (classDescriptor.isVisible())
150                 result++;
151
152         return result;
153     }
154
155     @Override
156     public boolean isVisible() {
157
158         // hide inherited methods
159         if (isInherited)
160             return false;
161
162         // hide common object methods
163         if (Utils.isCommonObjectMethod(methodName))
164             return false;
165
166         // hide common Enumeration methods
167         if (parentClass.isEnum && Utils.isEnumMethod(methodName))
168             return false;
169
170         // hide get/set methods for the field of the same name
171         if (methodName.startsWith("get") || methodName.startsWith("set"))
172             if (parentClass.hasFieldIgnoreCase(methodName.substring(3)))
173                 return false;
174
175         // hide is methods for the boolean field of the same name
176         if (methodName.startsWith("is")) {
177             final FieldDescriptor field = parentClass
178                     .getFieldIgnoreCase(methodName.substring(2));
179             if (field != null)
180                 if ("boolean".equals(field.getType().getFullyQualifiedName()))
181                     return false;
182         }
183
184         return true;
185
186     }
187
188     @Override
189     public int compareTo(MethodDescriptor that) {
190         if (this == that) return 0;
191
192         int comparisonResult = methodName.compareTo(that.methodName);
193         if (comparisonResult != 0) return comparisonResult;
194
195         return parentClass.compareTo(that.parentClass);
196     }
197 }