1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package net.sf.clirr.core.internal.checks;
21
22 import java.util.Comparator;
23
24 import net.sf.clirr.core.internal.ClassChangeCheck;
25 import net.sf.clirr.core.internal.AbstractDiffReporter;
26 import net.sf.clirr.core.internal.ApiDiffDispatcher;
27 import net.sf.clirr.core.internal.CoIterator;
28 import net.sf.clirr.core.internal.NameComparator;
29 import net.sf.clirr.core.spi.Field;
30 import net.sf.clirr.core.spi.JavaType;
31 import net.sf.clirr.core.spi.Scope;
32 import net.sf.clirr.core.ApiDifference;
33 import net.sf.clirr.core.Severity;
34 import net.sf.clirr.core.ScopeSelector;
35 import net.sf.clirr.core.Message;
36
37 /***
38 * Checks the fields of a class.
39 *
40 * @author lkuehne
41 */
42 public class FieldSetCheck
43 extends AbstractDiffReporter
44 implements ClassChangeCheck
45 {
46 private static final Message MSG_FIELD_ADDED = new Message(6000);
47 private static final Message MSG_FIELD_REMOVED = new Message(6001);
48 private static final Message MSG_FIELD_NOT_CONSTANT = new Message(6002);
49 private static final Message MSG_FIELD_CONSTANT_CHANGED = new Message(6003);
50 private static final Message MSG_FIELD_TYPE_CHANGED = new Message(6004);
51 private static final Message MSG_FIELD_NOW_NON_FINAL = new Message(6005);
52 private static final Message MSG_FIELD_NOW_FINAL = new Message(6006);
53 private static final Message MSG_FIELD_NOW_NON_STATIC = new Message(6007);
54 private static final Message MSG_FIELD_NOW_STATIC = new Message(6008);
55 private static final Message MSG_FIELD_MORE_ACCESSIBLE = new Message(6009);
56 private static final Message MSG_FIELD_LESS_ACCESSIBLE = new Message(6010);
57 private static final Message MSG_CONSTANT_FIELD_REMOVED = new Message(6011);
58
59 private static final Comparator COMPARATOR = new NameComparator();
60 private ScopeSelector scopeSelector;
61
62 public FieldSetCheck(ApiDiffDispatcher dispatcher, ScopeSelector scopeSelector)
63 {
64 super(dispatcher);
65 this.scopeSelector = scopeSelector;
66 }
67
68 public final boolean check(JavaType baselineClass, JavaType currentClass)
69 {
70 final Field[] baselineFields = baselineClass.getFields();
71 final Field[] currentFields = currentClass.getFields();
72
73 CoIterator iter = new CoIterator(
74 COMPARATOR, baselineFields, currentFields);
75
76 while (iter.hasNext())
77 {
78 iter.next();
79
80 Field bField = (Field) iter.getLeft();
81 Field cField = (Field) iter.getRight();
82
83 if (bField == null)
84 {
85 if (scopeSelector.isSelected(cField))
86 {
87 String scope = cField.getDeclaredScope().getDesc();
88 fireDiff(MSG_FIELD_ADDED,
89 Severity.INFO, currentClass, cField,
90 new String[]{scope});
91 }
92 }
93 else if (cField == null)
94 {
95 if (scopeSelector.isSelected(bField))
96 {
97 if ((bField.getConstantValue() != null) && bField.isFinal())
98 {
99
100
101
102
103
104
105
106 fireDiff(MSG_CONSTANT_FIELD_REMOVED,
107 getSeverity(baselineClass, bField, Severity.WARNING),
108 getSeverity(baselineClass, bField, Severity.ERROR),
109 baselineClass, bField, null);
110 }
111 else
112 {
113 fireDiff(MSG_FIELD_REMOVED,
114 getSeverity(baselineClass, bField, Severity.ERROR),
115 baselineClass, bField, null);
116 }
117 }
118 }
119 else if (scopeSelector.isSelected(bField) || scopeSelector.isSelected(cField))
120 {
121 checkForModifierChange(bField, cField, currentClass);
122 checkForVisibilityChange(bField, cField, currentClass);
123 checkForTypeChange(bField, cField, currentClass);
124 checkForConstantValueChange(bField, cField, currentClass);
125 }
126 }
127
128 return true;
129 }
130
131 private void checkForConstantValueChange(Field bField, Field cField, JavaType currentClass)
132 {
133 if (!(bField.isStatic() && bField.isFinal() && cField.isStatic() && cField.isFinal()))
134 {
135 return;
136 }
137
138 final Object bVal = bField.getConstantValue();
139
140 if (bVal != null)
141 {
142 final String bValRep = bVal.toString();
143 final Object cVal = cField.getConstantValue();
144 if (cVal == null)
145 {
146
147
148
149
150
151
152 fireDiff(MSG_FIELD_NOT_CONSTANT,
153 getSeverity(currentClass, bField, Severity.WARNING),
154 currentClass, cField, null);
155 return;
156 }
157
158 final String cValRep = String.valueOf(cVal);
159 if (!bValRep.equals(cValRep))
160 {
161
162
163
164
165 fireDiff(MSG_FIELD_CONSTANT_CHANGED,
166 getSeverity(currentClass, bField, Severity.WARNING),
167 currentClass, cField, null);
168 }
169 }
170 }
171
172 private void checkForTypeChange(Field bField, Field cField, JavaType currentClass)
173 {
174 final String bSig = bField.getType().toString();
175 final String cSig = cField.getType().toString();
176 if (!bSig.equals(cSig))
177 {
178 fireDiff(MSG_FIELD_TYPE_CHANGED,
179 getSeverity(currentClass, bField, Severity.ERROR),
180 currentClass, bField,
181 new String[] {bSig, cSig});
182 }
183 }
184
185 private void checkForModifierChange(Field bField, Field cField, JavaType clazz)
186 {
187 if (bField.isFinal() && !cField.isFinal())
188 {
189 fireDiff(MSG_FIELD_NOW_NON_FINAL,
190 Severity.INFO, clazz, cField, null);
191 }
192
193 if (!bField.isFinal() && cField.isFinal())
194 {
195 fireDiff(MSG_FIELD_NOW_FINAL, Severity.ERROR, clazz, cField, null);
196 }
197
198 if (bField.isStatic() && !cField.isStatic())
199 {
200 fireDiff(MSG_FIELD_NOW_NON_STATIC,
201 getSeverity(clazz, bField, Severity.ERROR),
202 clazz, cField, null);
203 }
204
205 if (!bField.isStatic() && cField.isStatic())
206 {
207 fireDiff(MSG_FIELD_NOW_STATIC,
208 getSeverity(clazz, bField, Severity.ERROR),
209 clazz, cField, null);
210 }
211
212
213
214
215
216 }
217
218 private void checkForVisibilityChange(Field bField, Field cField, JavaType clazz)
219 {
220 Scope bScope = bField.getEffectiveScope();
221 Scope cScope = cField.getEffectiveScope();
222
223 if (cScope.isMoreVisibleThan(bScope))
224 {
225 fireDiff(MSG_FIELD_MORE_ACCESSIBLE,
226 Severity.INFO, clazz, cField,
227 new String[] {bScope.getDesc(), cScope.getDesc()});
228 }
229 else if (cScope.isLessVisibleThan(bScope))
230 {
231 fireDiff(MSG_FIELD_LESS_ACCESSIBLE,
232 getSeverity(clazz, bField, Severity.ERROR),
233 clazz, cField,
234 new String[] {bScope.getDesc(), cScope.getDesc()});
235 }
236 }
237
238 private void fireDiff(
239 Message msg,
240 Severity severity,
241 JavaType clazz,
242 Field field,
243 String[] args)
244 {
245 fireDiff(msg, severity, severity, clazz, field, args);
246 }
247
248 private void fireDiff(
249 Message msg,
250 Severity binarySeverity,
251 Severity sourceSeverity,
252 JavaType clazz,
253 Field field,
254 String[] args)
255 {
256 final String className = clazz.getName();
257 final ApiDifference diff =
258 new ApiDifference(
259 msg,
260 binarySeverity, sourceSeverity,
261 className, null, field.getName(), args);
262 getApiDiffDispatcher().fireDiff(diff);
263 }
264 }