3f7acef654aae6118b23b01aa3a92937a1a11b38
[javainspect.git] / src / main / java / eu / svjatoslav / inspector / java / structure / MethodDescriptor.java
1 /*
2  * JavaInspect - Utility to visualize java software
3  * Copyright (C) 2013-2017, 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 == null) return result.toString();
102         if (!returnType.isVisible()) 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\">" + describeReturnType()
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     private String describeReturnType() {
133         if (returnType == null) return "-null-";
134
135         return returnType.getClassName(true);
136     }
137
138     @Override
139     public String getGraphId() {
140         return parentClass.getGraphId() + ":" + methodName;
141     }
142
143     private String getMethodLabel() {
144         return methodName;
145     }
146
147     protected int getOutsideVisibleReferencesCount() {
148         int result = 0;
149
150         if (returnType != null)
151             if (returnType.isVisible())
152                 result++;
153
154         for (final ClassDescriptor classDescriptor : argumentTypes)
155             if (classDescriptor.isVisible())
156                 result++;
157
158         return result;
159     }
160
161     @Override
162     public boolean isVisible() {
163
164         // hide inherited methods
165         if (isInherited)
166             return false;
167
168         // hide common object methods
169         if (Utils.isCommonObjectMethod(methodName))
170             return false;
171
172         // hide common Enumeration methods
173         if (parentClass.isEnum && Utils.isEnumMethod(methodName))
174             return false;
175
176         // hide get/set methods for the field of the same name
177         if (methodName.startsWith("get") || methodName.startsWith("set"))
178             if (parentClass.hasFieldIgnoreCase(methodName.substring(3)))
179                 return false;
180
181         // hide is methods for the boolean field of the same name
182         if (methodName.startsWith("is")) {
183             final FieldDescriptor field = parentClass
184                     .getFieldIgnoreCase(methodName.substring(2));
185             if (field != null)
186                 if ("boolean".equals(field.getType().getFullyQualifiedName()))
187                     return false;
188         }
189
190         return true;
191
192     }
193
194     @Override
195     public int compareTo(MethodDescriptor that) {
196         if (this == that) return 0;
197
198         int comparisonResult = methodName.compareTo(that.methodName);
199         if (comparisonResult != 0) return comparisonResult;
200
201         return parentClass.compareTo(that.parentClass);
202     }
203 }