432ec99bdc068d146eb9d1cb7d1be45d7f5a7711
[javainspect.git] / src / main / java / eu / svjatoslav / inspector / java / structure / FieldDescriptor.java
1 /*
2  * JavaInspect - Utility to visualize java software
3  * Copyright (C) 2013-2019, 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.Field;
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 field within a java class.
20  */
21
22 public class FieldDescriptor implements GraphElement {
23
24     private final ClassDescriptor parentClassDescriptor;
25     private final List<ClassDescriptor> typeArguments = new ArrayList<>();
26     private String name;
27     private ClassDescriptor type;
28     private boolean isInherited;
29
30     public FieldDescriptor(final ClassDescriptor parent) {
31         parentClassDescriptor = parent;
32     }
33
34     public void analyzeField(final Field field) {
35
36         if (!field.getDeclaringClass().getName()
37                 .equals(parentClassDescriptor.getFullyQualifiedName()))
38             isInherited = true;
39
40         name = field.getName();
41         type = parentClassDescriptor.getClassGraph().getOrCreateClassDescriptor(
42                 field.getType());
43         type.registerReference();
44
45         final Type fieldGenericType = field.getGenericType();
46         if (fieldGenericType instanceof ParameterizedType) {
47             final ParameterizedType fieldParameterizedGenericType = (ParameterizedType) fieldGenericType;
48             for (final Type type : fieldParameterizedGenericType.getActualTypeArguments())
49                 if (type instanceof Class) {
50                     final Class aClass = (Class) type;
51                     final ClassDescriptor genericTypeDescriptor = parentClassDescriptor
52                             .getClassGraph().getOrCreateClassDescriptor(aClass);
53                     genericTypeDescriptor.registerReference();
54                     typeArguments.add(genericTypeDescriptor);
55                 }
56
57         }
58     }
59
60     @Override
61     public String getDot() {
62
63         if (!isVisible())
64             return "";
65
66         final StringBuilder result = new StringBuilder();
67
68         // describe associated types
69         for (final ClassDescriptor classDescriptor : typeArguments)
70             if (classDescriptor.isVisible())
71                 if (classDescriptor.areReferencesShown())
72                     result.append("    " + getGraphId() + " -> "
73                             + classDescriptor.getGraphId() + "[label=\"" + name
74                             + "\", color=\"" + classDescriptor.getColor()
75                             + "\", style=\"bold\"];\n");
76
77         if (type == null) return result.toString();
78         if (!type.isVisible())
79             return result.toString();
80
81         // main type
82         boolean showLink = type.areReferencesShown();
83
84         if (type == parentClassDescriptor)
85             showLink = false;
86
87         if (parentClassDescriptor.isEnum)
88             showLink = false;
89
90         if (showLink)
91             result.append("    " + getGraphId() + " -> " + type.getGraphId()
92                     + "[label=\"" + name + "\"," + " color=\""
93                     + type.getColor() + "\", style=\"bold\"];\n");
94
95         return result.toString();
96     }
97
98     @Override
99     public String getEmbeddedDot() {
100
101         if (!isVisible())
102             return "";
103
104         final StringBuilder result = new StringBuilder();
105
106         result.append("        // " + name + "\n");
107         if (parentClassDescriptor.isEnum && (type == parentClassDescriptor)) {
108             result.append("        <TR><TD colspan=\"2\" PORT=\"" + name);
109             result.append("\" ALIGN=\"left\"><FONT POINT-SIZE=\"11.0\">");
110             result.append(name + "</FONT></TD></TR>\n");
111         } else {
112             result.append("        <TR><td ALIGN=\"right\">");
113             result.append("<FONT POINT-SIZE=\"8.0\">");
114             result.append(describeType() + "</FONT>");
115             result.append("</td><TD PORT=\"" + name);
116             result.append("\" ALIGN=\"left\"><FONT POINT-SIZE=\"11.0\">");
117             result.append(name + "</FONT></TD></TR>\n");
118         }
119         return result.toString();
120     }
121
122     private String describeType() {
123         if (type == null) return "-null-";
124         return type.getClassName(true);
125     }
126
127     @Override
128     public String getGraphId() {
129         return parentClassDescriptor.getGraphId() + ":" + name;
130     }
131
132     protected int getOutsideVisibleReferencesCount() {
133
134         if (!isVisible())
135             return 0;
136
137         if (type != null)
138             if (type.isVisible())
139                 return 1;
140
141         return 0;
142     }
143
144     protected ClassDescriptor getType() {
145         return type;
146     }
147
148     @Override
149     public boolean isVisible() {
150         if (isInherited)
151             return false;
152
153         if (name.contains("$"))
154             return false;
155
156         return !name.equals("serialVersionUID");
157
158     }
159
160 }