KickJava   Java API By Example, From Geeks To Geeks.

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


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 net.sf.clirr.core.Severity;
23 import net.sf.clirr.core.Message;
24 import net.sf.clirr.core.internal.AbstractDiffReporter;
25 import net.sf.clirr.core.internal.ApiDiffDispatcher;
26 import net.sf.clirr.core.internal.ClassChangeCheck;
27 import net.sf.clirr.core.spi.JavaType;
28 import net.sf.clirr.core.spi.Method;
29 import net.sf.clirr.core.spi.Scope;
30
31 /**
32  * Detects changes in class modifiers (abstract, final).
33  *
34  * @author lkuehne
35  */

36 public final class ClassModifierCheck
37     extends AbstractDiffReporter
38     implements ClassChangeCheck
39 {
40     private static final Message MSG_MODIFIER_UNABLE_TO_DETERMINE_CLASS_SCOPE = new Message(3000);
41     private static final Message MSG_MODIFIER_REMOVED_FINAL = new Message(3001);
42     private static final Message MSG_MODIFIER_ADDED_FINAL_TO_EFFECTIVE_FINAL = new Message(3002);
43     private static final Message MSG_MODIFIER_ADDED_FINAL = new Message(3003);
44     private static final Message MSG_MODIFIER_REMOVED_ABSTRACT = new Message(3004);
45     private static final Message MSG_MODIFIER_ADDED_ABSTRACT = new Message(3005);
46
47     /**
48      * Create a new instance of this check.
49      * @param dispatcher the diff dispatcher that distributes the detected changes to the listeners.
50      */

51     public ClassModifierCheck(ApiDiffDispatcher dispatcher)
52     {
53         super(dispatcher);
54     }
55
56     /** {@inheritDoc} */
57     public boolean check(JavaType compatBaseLine, JavaType currentVersion)
58     {
59         final String JavaDoc className = compatBaseLine.getName();
60
61         Scope currentScope = currentVersion.getEffectiveScope();
62         if (currentScope.isLessVisibleThan(Scope.PACKAGE))
63         {
64             // for private classes, we don't care if they are now final,
65
// or now abstract, or now an interface.
66
return true;
67         }
68
69         final boolean currentIsFinal = currentVersion.isFinal();
70         final boolean compatIsFinal = compatBaseLine.isFinal();
71         final boolean currentIsAbstract = currentVersion.isAbstract();
72         final boolean compatIsAbstract = compatBaseLine.isAbstract();
73         final boolean currentIsInterface = currentVersion.isInterface();
74         final boolean compatIsInterface = compatBaseLine.isInterface();
75
76         if (compatIsFinal && !currentIsFinal)
77         {
78             log(MSG_MODIFIER_REMOVED_FINAL,
79                     Severity.INFO, className, null, null, null);
80         }
81         else if (!compatIsFinal && currentIsFinal)
82         {
83             if (isEffectivelyFinal(compatBaseLine))
84             {
85                 log(MSG_MODIFIER_ADDED_FINAL_TO_EFFECTIVE_FINAL,
86                         Severity.INFO, className, null, null, null);
87             }
88             else
89             {
90                 log(MSG_MODIFIER_ADDED_FINAL,
91                         getSeverity(compatBaseLine, Severity.ERROR),
92                         className, null, null, null);
93             }
94         }
95
96         // interfaces are always abstract, don't report gender change here
97
if (compatIsAbstract && !currentIsAbstract && !compatIsInterface)
98         {
99             log(MSG_MODIFIER_REMOVED_ABSTRACT,
100                     Severity.INFO, className, null, null, null);
101         }
102         else if (!compatIsAbstract && currentIsAbstract && !currentIsInterface)
103         {
104             log(MSG_MODIFIER_ADDED_ABSTRACT,
105                     getSeverity(compatBaseLine, Severity.ERROR),
106                     className, null, null, null);
107         }
108
109         return true;
110     }
111
112     /**
113      * There are cases where nonfinal classes are effectively final
114      * because they do not have public or protected ctors. For such
115      * classes we should not emit errors when a final modifier is
116      * introduced.
117      */

118     private boolean isEffectivelyFinal(JavaType clazz)
119     {
120         if (clazz.isFinal())
121         {
122             return true;
123         }
124
125         // iterate over all constructors, and detect whether any are
126
// public or protected. If so, return false.
127
Method[] methods = clazz.getMethods();
128         for (int i = 0; i < methods.length; ++i)
129         {
130             Method method = methods[i];
131             final String JavaDoc methodName = method.getName();
132             if (methodName.equals("<init>"))
133             {
134                 if (method.getEffectiveScope().isMoreVisibleThan(Scope.PACKAGE))
135                 {
136                     return false;
137                 }
138             }
139         }
140
141         // no public or protected constructor found
142
return true;
143     }
144 }
145
Popular Tags