KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > clirr > core > internal > checks > FieldSetCheck


1 //////////////////////////////////////////////////////////////////////////////
2
// Clirr: compares two versions of a java library for binary compatibility
3
// Copyright (C) 2003 - 2005 Lars Kühne
4
//
5
// This library is free software; you can redistribute it and/or
6
// modify it under the terms of the GNU Lesser General Public
7
// License as published by the Free Software Foundation; either
8
// version 2.1 of the License, or (at your option) any later version.
9
//
10
// This library is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
// Lesser General Public License for more details.
14
//
15
// You should have received a copy of the GNU Lesser General Public
16
// License along with this library; if not, write to the Free Software
17
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
//////////////////////////////////////////////////////////////////////////////
19

20 package net.sf.clirr.core.internal.checks;
21
22 import java.util.Comparator JavaDoc;
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 JavaDoc 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 JavaDoc scope = cField.getDeclaredScope().getDesc();
88                     fireDiff(MSG_FIELD_ADDED,
89                         Severity.INFO, currentClass, cField,
90                         new String JavaDoc[]{scope});
91                 }
92             }
93             else if (cField == null)
94             {
95                 if (scopeSelector.isSelected(bField))
96                 {
97                     if ((bField.getConstantValue() != null) && bField.isFinal())
98                     {
99                         // Fields which are compile-time constants will have
100
// been inlined into callers; even though the field
101
// has been deleted, the caller will continue to use
102
// the old value. The result is therefore not
103
// technically a binary incompatibility, though it is
104
// a source-code incompatibility.
105
// See bugtracker #961222
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 JavaDoc bVal = bField.getConstantValue();
139
140         if (bVal != null)
141         {
142             final String JavaDoc bValRep = bVal.toString();
143             final Object JavaDoc cVal = cField.getConstantValue();
144             if (cVal == null)
145             {
146                 // TODO: also check whether old field is final. If it's not
147
// final, then external code cannot have inlined the
148
// constant, and therefore we can issue an INFO instead
149
// of a warning. Actually, may be better to introduce a
150
// different message code rather than issue this code with
151
// two different severity levels..
152
fireDiff(MSG_FIELD_NOT_CONSTANT,
153                         getSeverity(currentClass, bField, Severity.WARNING),
154                         currentClass, cField, null);
155                 return;
156             }
157
158             final String JavaDoc cValRep = String.valueOf(cVal);
159             if (!bValRep.equals(cValRep))
160             {
161                 // TODO: print out old and new value
162
// How can that be done with BCEL, esp. for boolean values?
163
//
164
// TODO: also check whether field is final (see above).
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 JavaDoc bSig = bField.getType().toString();
175         final String JavaDoc 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 JavaDoc[] {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         // JLS, 13.4.10: Adding or deleting a transient modifier of a field
213
// does not break compatibility with pre-existing binaries
214

215         // TODO: What about volatile?
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 JavaDoc[] {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 JavaDoc[] {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 JavaDoc[] 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 JavaDoc[] args)
255     {
256         final String JavaDoc 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 }
265
Popular Tags