Thread: [Clirr-devel] CVS: clirr/core/src/java/net/sf/clirr/core/internal/checks ClassHierarchyCheck.java,NO
Status: Alpha
                
                Brought to you by:
                
                    lkuehne
                    
                
            | 
     
      
      
      From:  <lk...@us...> - 2004-07-10 13:37:41
       
   | 
Update of /cvsroot/clirr/clirr/core/src/java/net/sf/clirr/core/internal/checks In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23600/src/java/net/sf/clirr/core/internal/checks Added Files: ClassHierarchyCheck.java ClassModifierCheck.java ClassScopeCheck.java FieldSetCheck.java GenderChangeCheck.java InterfaceSetCheck.java MethodSetCheck.java package.html Log Message: moving from root directory to core --- NEW FILE --- ////////////////////////////////////////////////////////////////////////////// // Clirr: compares two versions of a java library for binary compatibility // Copyright (C) 2003 - 2004 Lars Kühne // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ////////////////////////////////////////////////////////////////////////////// package net.sf.clirr.core.internal.checks; import net.sf.clirr.core.Message; import net.sf.clirr.core.internal.AbstractDiffReporter; import net.sf.clirr.core.internal.ApiDiffDispatcher; import net.sf.clirr.core.internal.ClassChangeCheck; import net.sf.clirr.core.internal.CoIterator; import net.sf.clirr.core.internal.JavaClassNameComparator; import org.apache.bcel.classfile.JavaClass; /** * Detects changes in the set of superclasses. * * @author lkuehne */ public final class ClassHierarchyCheck extends AbstractDiffReporter implements ClassChangeCheck { private static final Message MSG_ADDED_CLASS_TO_SUPERCLASSES = new Message(5000); private static final Message MSG_REMOVED_CLASS_FROM_SUPERCLASSES = new Message(5001); /** * Create a new instance of this check. * @param dispatcher the diff dispatcher that distributes the detected changes to the listeners. */ public ClassHierarchyCheck(ApiDiffDispatcher dispatcher) { super(dispatcher); } /** {@inheritDoc} */ public boolean check(JavaClass compatBaseline, JavaClass currentVersion) { JavaClass[] compatSupers = compatBaseline.getSuperClasses(); JavaClass[] currentSupers = currentVersion.getSuperClasses(); boolean isThrowable = false; for (int i = 0; i < compatSupers.length; i++) { JavaClass javaClass = compatSupers[i]; if ("java.lang.Throwable".equals(javaClass.getClassName())) { isThrowable = true; } } final String className = compatBaseline.getClassName(); CoIterator iter = new CoIterator(JavaClassNameComparator.COMPARATOR, compatSupers, currentSupers); while (iter.hasNext()) { iter.next(); JavaClass baselineSuper = (JavaClass) iter.getLeft(); JavaClass currentSuper = (JavaClass) iter.getRight(); if (baselineSuper == null) { net.sf.clirr.core.Severity severity; if (isThrowable) { severity = net.sf.clirr.core.Severity.WARNING; } else { severity = net.sf.clirr.core.Severity.INFO; } log(MSG_ADDED_CLASS_TO_SUPERCLASSES, severity, className, null, null, new String[]{currentSuper.getClassName()}); } else if (currentSuper == null) { log(MSG_REMOVED_CLASS_FROM_SUPERCLASSES, net.sf.clirr.core.Severity.ERROR, className, null, null, new String[]{baselineSuper.getClassName()}); } } return true; } } --- NEW FILE --- ////////////////////////////////////////////////////////////////////////////// // Clirr: compares two versions of a java library for binary compatibility // Copyright (C) 2003 - 2004 Lars Kühne // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ////////////////////////////////////////////////////////////////////////////// package net.sf.clirr.core.internal.checks; import net.sf.clirr.core.Severity; import net.sf.clirr.core.Message; import net.sf.clirr.core.internal.AbstractDiffReporter; import net.sf.clirr.core.internal.ApiDiffDispatcher; import net.sf.clirr.core.internal.ClassChangeCheck; import net.sf.clirr.core.CheckerException; import net.sf.clirr.core.ScopeSelector; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.Method; /** * Detects changes in class modifiers (abstract, final). * * @author lkuehne */ public final class ClassModifierCheck extends AbstractDiffReporter implements ClassChangeCheck { private static final net.sf.clirr.core.Message MSG_MODIFIER_UNABLE_TO_DETERMINE_CLASS_SCOPE = new Message(3000); private static final net.sf.clirr.core.Message MSG_MODIFIER_REMOVED_FINAL = new Message(3001); private static final net.sf.clirr.core.Message MSG_MODIFIER_ADDED_FINAL_TO_EFFECTIVE_FINAL = new Message(3002); private static final net.sf.clirr.core.Message MSG_MODIFIER_ADDED_FINAL = new Message(3003); private static final net.sf.clirr.core.Message MSG_MODIFIER_REMOVED_ABSTRACT = new Message(3004); private static final net.sf.clirr.core.Message MSG_MODIFIER_ADDED_ABSTRACT = new Message(3005); /** * Create a new instance of this check. * @param dispatcher the diff dispatcher that distributes the detected changes to the listeners. */ public ClassModifierCheck(ApiDiffDispatcher dispatcher) { super(dispatcher); } /** {@inheritDoc} */ public boolean check(JavaClass compatBaseLine, JavaClass currentVersion) { final String className = compatBaseLine.getClassName(); try { net.sf.clirr.core.ScopeSelector.Scope currentScope = net.sf.clirr.core.ScopeSelector.getClassScope(currentVersion); if (currentScope == net.sf.clirr.core.ScopeSelector.SCOPE_PRIVATE) { // for private classes, we don't care if they are now final, // or now abstract, or now an interface. return true; } } catch (CheckerException ex) { log(MSG_MODIFIER_UNABLE_TO_DETERMINE_CLASS_SCOPE, net.sf.clirr.core.Severity.ERROR, className, null, null, null); return true; } final boolean currentIsFinal = currentVersion.isFinal(); final boolean compatIsFinal = compatBaseLine.isFinal(); final boolean currentIsAbstract = currentVersion.isAbstract(); final boolean compatIsAbstract = compatBaseLine.isAbstract(); final boolean currentIsInterface = currentVersion.isInterface(); final boolean compatIsInterface = compatBaseLine.isInterface(); if (compatIsFinal && !currentIsFinal) { log(MSG_MODIFIER_REMOVED_FINAL, net.sf.clirr.core.Severity.INFO, className, null, null, null); } else if (!compatIsFinal && currentIsFinal) { if (isEffectivelyFinal(compatBaseLine)) { log(MSG_MODIFIER_ADDED_FINAL_TO_EFFECTIVE_FINAL, net.sf.clirr.core.Severity.INFO, className, null, null, null); } else { log(MSG_MODIFIER_ADDED_FINAL, net.sf.clirr.core.Severity.ERROR, className, null, null, null); } } // interfaces are always abstract, don't report gender change here if (compatIsAbstract && !currentIsAbstract && !compatIsInterface) { log(MSG_MODIFIER_REMOVED_ABSTRACT, net.sf.clirr.core.Severity.INFO, className, null, null, null); } else if (!compatIsAbstract && currentIsAbstract && !currentIsInterface) { log(MSG_MODIFIER_ADDED_ABSTRACT, net.sf.clirr.core.Severity.ERROR, className, null, null, null); } return true; } /** * There are cases where nonfinal classes are effectively final * because they do not have public or protected ctors. For such * classes we should not emit errors when a final modifier is * introduced. */ private boolean isEffectivelyFinal(JavaClass clazz) { if (clazz.isFinal()) { return true; } // iterate over all constructors, and detect whether any are // public or protected. If so, return false. Method[] methods = clazz.getMethods(); for (int i = 0; i < methods.length; ++i) { Method method = methods[i]; final String methodName = method.getName(); if (methodName.equals("<init>")) { if (method.isPublic() || method.isProtected()) { return false; } } } // no public or protected constructor found return true; } } --- NEW FILE --- ////////////////////////////////////////////////////////////////////////////// // Clirr: compares two versions of a java library for binary compatibility // Copyright (C) 2003 - 2004 Lars Kühne // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ////////////////////////////////////////////////////////////////////////////// package net.sf.clirr.core.internal.checks; import net.sf.clirr.core.Severity; import net.sf.clirr.core.ScopeSelector; import net.sf.clirr.core.Message; import net.sf.clirr.core.internal.AbstractDiffReporter; import net.sf.clirr.core.internal.ApiDiffDispatcher; import net.sf.clirr.core.internal.ClassChangeCheck; import net.sf.clirr.core.CheckerException; import org.apache.bcel.classfile.JavaClass; /** * Detects changes in class access declaration, for both "top-level" classes, * and nested classes. * <p> * Java class files only ever contain scope specifiers of "public" or "package". * For top-level classes, this is expected: it is not possible to have a * top-level protected or private class. * <p> * However nested classes <i>can</i> be declared as protected or private. The * way to tell the real scope of a nested class is to ignore the scope in * the actual class file itself, and instead look in the "InnerClasses" * attribute stored on the enclosing class. This is exactly what the java * compiler does when compiling, and what the jvm does when verifying class * linkage at runtime. * * @author Simon Kitching */ public final class ClassScopeCheck extends AbstractDiffReporter implements ClassChangeCheck { private static final net.sf.clirr.core.Message MSG_SCOPE_INCREASED = new Message(1000); private static final net.sf.clirr.core.Message MSG_SCOPE_DECREASED = new Message(1001); private static final net.sf.clirr.core.Message MSG_ERROR_DETERMINING_SCOPE_OLD = new Message(1002); private static final net.sf.clirr.core.Message MSG_ERROR_DETERMINING_SCOPE_NEW = new Message(1003); private net.sf.clirr.core.ScopeSelector scopeSelector; /** * Create a new instance of this check. * @param dispatcher the diff dispatcher that distributes the detected changes to the listeners. */ public ClassScopeCheck(ApiDiffDispatcher dispatcher, net.sf.clirr.core.ScopeSelector scopeSelector) { super(dispatcher); this.scopeSelector = scopeSelector; } /** {@inheritDoc} */ public boolean check(JavaClass compatBaseline, JavaClass currentVersion) { net.sf.clirr.core.ScopeSelector.Scope bScope; try { bScope = net.sf.clirr.core.ScopeSelector.getClassScope(compatBaseline); } catch (CheckerException ex) { log(MSG_ERROR_DETERMINING_SCOPE_OLD, net.sf.clirr.core.Severity.ERROR, compatBaseline.getClassName(), null, null, new String[]{ex.getMessage()}); return false; } net.sf.clirr.core.ScopeSelector.Scope cScope; try { cScope = net.sf.clirr.core.ScopeSelector.getClassScope(currentVersion); } catch (CheckerException ex) { log(MSG_ERROR_DETERMINING_SCOPE_NEW, net.sf.clirr.core.Severity.ERROR, compatBaseline.getClassName(), null, null, new String[]{ex.getMessage()}); return false; } if (!scopeSelector.isSelected(bScope) && !scopeSelector.isSelected(cScope)) { // neither the old nor the new class are "visible" at the scope // the user of this class cares about, so just skip this test // and all following tests for this pair of classes. return false; } if (cScope.isMoreVisibleThan(bScope)) { String[] args = {bScope.getDesc(), cScope.getDesc()}; log(MSG_SCOPE_INCREASED, net.sf.clirr.core.Severity.INFO, compatBaseline.getClassName(), null, null, args); } else if (cScope.isLessVisibleThan(bScope)) { String[] args = {bScope.getDesc(), cScope.getDesc()}; log(MSG_SCOPE_DECREASED, net.sf.clirr.core.Severity.ERROR, compatBaseline.getClassName(), null, null, args); } // Apply further checks only if both versions of the class have scopes // of interest. For example, when the user is only interested in // public & protected classes, then for classes which have just become // public/protected we just want to report that it is now "visible"; // because the class was not visible before the differences since its // last version are not relevant. And for classes which are no longer // public/protected, we just want to report that the whole class is no // longer "visible"; as it is not visible to users any changes to it // are irrelevant. return scopeSelector.isSelected(bScope) && scopeSelector.isSelected(cScope); } } --- NEW FILE --- ////////////////////////////////////////////////////////////////////////////// // Clirr: compares two versions of a java library for binary compatibility // Copyright (C) 2003 - 2004 Lars Kühne // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ////////////////////////////////////////////////////////////////////////////// package net.sf.clirr.core.internal.checks; import java.util.Comparator; import net.sf.clirr.core.internal.ClassChangeCheck; import net.sf.clirr.core.internal.AbstractDiffReporter; import net.sf.clirr.core.internal.ApiDiffDispatcher; import net.sf.clirr.core.internal.CoIterator; import net.sf.clirr.core.ApiDifference; import net.sf.clirr.core.Severity; import net.sf.clirr.core.ScopeSelector; import net.sf.clirr.core.Message; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.Field; import org.apache.bcel.classfile.ConstantValue; /** * Checks the fields of a class. * * @author lkuehne */ public class FieldSetCheck extends AbstractDiffReporter implements ClassChangeCheck { private static final net.sf.clirr.core.Message MSG_FIELD_ADDED = new Message(6000); private static final net.sf.clirr.core.Message MSG_FIELD_REMOVED = new Message(6001); private static final net.sf.clirr.core.Message MSG_FIELD_NOT_CONSTANT = new Message(6002); private static final net.sf.clirr.core.Message MSG_FIELD_CONSTANT_CHANGED = new Message(6003); private static final net.sf.clirr.core.Message MSG_FIELD_TYPE_CHANGED = new Message(6004); private static final net.sf.clirr.core.Message MSG_FIELD_NOW_NON_FINAL = new Message(6005); private static final net.sf.clirr.core.Message MSG_FIELD_NOW_FINAL = new Message(6006); private static final net.sf.clirr.core.Message MSG_FIELD_NOW_NON_STATIC = new Message(6007); private static final net.sf.clirr.core.Message MSG_FIELD_NOW_STATIC = new Message(6008); private static final net.sf.clirr.core.Message MSG_FIELD_MORE_ACCESSABLE = new Message(6009); private static final net.sf.clirr.core.Message MSG_FIELD_LESS_ACCESSABLE = new Message(6010); private static final class FieldNameComparator implements Comparator { public int compare(Object o1, Object o2) { Field f1 = (Field) o1; Field f2 = (Field) o2; final String name1 = f1.getName(); final String name2 = f2.getName(); return name1.compareTo(name2); } } private static final Comparator COMPARATOR = new FieldNameComparator(); private net.sf.clirr.core.ScopeSelector scopeSelector; public FieldSetCheck(ApiDiffDispatcher dispatcher, net.sf.clirr.core.ScopeSelector scopeSelector) { super(dispatcher); this.scopeSelector = scopeSelector; } public final boolean check(JavaClass baselineClass, JavaClass currentClass) { final Field[] baselineFields = baselineClass.getFields(); final Field[] currentFields = currentClass.getFields(); CoIterator iter = new CoIterator(COMPARATOR, baselineFields, currentFields); while (iter.hasNext()) { iter.next(); Field bField = (Field) iter.getLeft(); Field cField = (Field) iter.getRight(); if (bField == null) { if (scopeSelector.isSelected(cField)) { final String name = cField.getName(); String scope = net.sf.clirr.core.ScopeSelector.getScopeDesc(cField); fireDiff(MSG_FIELD_ADDED, net.sf.clirr.core.Severity.INFO, currentClass, cField, new String[]{scope}); } } else if (cField == null) { if (scopeSelector.isSelected(bField)) { final String name = bField.getName(); fireDiff(MSG_FIELD_REMOVED, net.sf.clirr.core.Severity.ERROR, baselineClass, bField, null); } } else if (scopeSelector.isSelected(bField) || scopeSelector.isSelected(cField)) { checkForModifierChange(bField, cField, currentClass); checkForVisibilityChange(bField, cField, currentClass); checkForTypeChange(bField, cField, currentClass); checkForConstantValueChange(bField, cField, currentClass); } } return true; } private void checkForConstantValueChange(Field bField, Field cField, JavaClass currentClass) { if (!(bField.isStatic() && bField.isFinal() && cField.isStatic() && cField.isFinal())) { return; } final ConstantValue bVal = bField.getConstantValue(); if (bVal != null) { final String bValRep = bVal.toString(); final ConstantValue cVal = cField.getConstantValue(); if (cVal == null) { fireDiff(MSG_FIELD_NOT_CONSTANT, net.sf.clirr.core.Severity.WARNING, currentClass, cField, null); return; } final String cValRep = String.valueOf(cVal); if (!bValRep.equals(cValRep)) { // TODO: print out old and new value // How can that be done with BCEL, esp. for boolean values? fireDiff(MSG_FIELD_CONSTANT_CHANGED, net.sf.clirr.core.Severity.WARNING, currentClass, cField, null); } } } private void checkForTypeChange(Field bField, Field cField, JavaClass currentClass) { final String bSig = bField.getType().toString(); final String cSig = cField.getType().toString(); if (!bSig.equals(cSig)) { fireDiff(MSG_FIELD_TYPE_CHANGED, net.sf.clirr.core.Severity.ERROR, currentClass, bField, new String[]{bSig, cSig}); } } private void checkForModifierChange(Field bField, Field cField, JavaClass clazz) { if (bField.isFinal() && !cField.isFinal()) { fireDiff(MSG_FIELD_NOW_NON_FINAL, net.sf.clirr.core.Severity.INFO, clazz, cField, null); } if (!bField.isFinal() && cField.isFinal()) { fireDiff(MSG_FIELD_NOW_FINAL, net.sf.clirr.core.Severity.ERROR, clazz, cField, null); } if (bField.isStatic() && !cField.isStatic()) { fireDiff(MSG_FIELD_NOW_NON_STATIC, net.sf.clirr.core.Severity.ERROR, clazz, cField, null); } if (!bField.isStatic() && cField.isStatic()) { fireDiff(MSG_FIELD_NOW_STATIC, net.sf.clirr.core.Severity.ERROR, clazz, cField, null); } // JLS, 13.4.10: Adding or deleting a transient modifier of a field // does not break compatibility with pre-existing binaries // TODO: What about volatile? } private void checkForVisibilityChange(Field bField, Field cField, JavaClass clazz) { net.sf.clirr.core.ScopeSelector.Scope bScope = net.sf.clirr.core.ScopeSelector.getScope(bField); net.sf.clirr.core.ScopeSelector.Scope cScope = net.sf.clirr.core.ScopeSelector.getScope(cField); if (cScope.isMoreVisibleThan(bScope)) { fireDiff(MSG_FIELD_MORE_ACCESSABLE, net.sf.clirr.core.Severity.INFO, clazz, cField, new String[]{bScope.getDesc(), cScope.getDesc()}); } else if (cScope.isLessVisibleThan(bScope)) { fireDiff(MSG_FIELD_LESS_ACCESSABLE, net.sf.clirr.core.Severity.ERROR, clazz, cField, new String[]{bScope.getDesc(), cScope.getDesc()}); } } private void fireDiff(net.sf.clirr.core.Message msg, net.sf.clirr.core.Severity severity, JavaClass clazz, Field field, String[] args) { final String className = clazz.getClassName(); final net.sf.clirr.core.ApiDifference diff = new ApiDifference(msg, severity, className, null, field.getName(), args); getApiDiffDispatcher().fireDiff(diff); } } --- NEW FILE --- ////////////////////////////////////////////////////////////////////////////// // Clirr: compares two versions of a java library for binary compatibility // Copyright (C) 2003 - 2004 Lars Kühne // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ////////////////////////////////////////////////////////////////////////////// package net.sf.clirr.core.internal.checks; import net.sf.clirr.core.Severity; import net.sf.clirr.core.Message; import net.sf.clirr.core.internal.AbstractDiffReporter; import net.sf.clirr.core.internal.ApiDiffDispatcher; import net.sf.clirr.core.internal.ClassChangeCheck; import org.apache.bcel.classfile.JavaClass; /** * Detects gender changes (a class became an interface or vice versa). * * @author lkuehne */ public final class GenderChangeCheck extends AbstractDiffReporter implements ClassChangeCheck { private static final net.sf.clirr.core.Message MSG_GENDER_CLASS_TO_INTERFACE = new Message(2000); private static final net.sf.clirr.core.Message MSG_GENDER_INTERFACE_TO_CLASS = new Message(2001); /** * Create a new instance of this check. * @param dispatcher the diff dispatcher that distributes the detected changes to the listeners. */ public GenderChangeCheck(ApiDiffDispatcher dispatcher) { super(dispatcher); } /** {@inheritDoc} */ public boolean check(JavaClass baseLine, JavaClass current) { if (baseLine.isClass() && current.isInterface()) { log(MSG_GENDER_CLASS_TO_INTERFACE, net.sf.clirr.core.Severity.ERROR, baseLine.getClassName(), null, null, null); } else if (baseLine.isInterface() && current.isClass()) { log(MSG_GENDER_INTERFACE_TO_CLASS, net.sf.clirr.core.Severity.ERROR, baseLine.getClassName(), null, null, null); } return true; } } --- NEW FILE --- ////////////////////////////////////////////////////////////////////////////// // Clirr: compares two versions of a java library for binary compatibility // Copyright (C) 2003 - 2004 Lars Kühne // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ////////////////////////////////////////////////////////////////////////////// package net.sf.clirr.core.internal.checks; import java.util.HashSet; import java.util.Set; import net.sf.clirr.core.Severity; import net.sf.clirr.core.Message; import net.sf.clirr.core.internal.AbstractDiffReporter; import net.sf.clirr.core.internal.ApiDiffDispatcher; import net.sf.clirr.core.internal.ClassChangeCheck; import net.sf.clirr.core.internal.CoIterator; import net.sf.clirr.core.internal.JavaClassNameComparator; import org.apache.bcel.classfile.JavaClass; /** * Detects changes in the set of interfaces implemented by a class. * * @author lkuehne */ public final class InterfaceSetCheck extends AbstractDiffReporter implements ClassChangeCheck { private static final net.sf.clirr.core.Message MSG_IFACE_ADDED = new Message(4000); private static final net.sf.clirr.core.Message MSG_IFACE_REMOVED = new Message(4001); /** * Create a new instance of this check. * @param dispatcher the diff dispatcher that distributes the detected changes to the listeners. */ public InterfaceSetCheck(ApiDiffDispatcher dispatcher) { super(dispatcher); } /** {@inheritDoc} */ public boolean check(JavaClass compatBaseline, JavaClass currentVersion) { JavaClass[] compatInterfaces = compatBaseline.getAllInterfaces(); JavaClass[] currentInterfaces = currentVersion.getAllInterfaces(); // Note: getAllInterfaces might return multiple array entries with the same // interface, so we need to use sets to remove duplicates... Set compat = createClassSet(compatInterfaces); Set current = createClassSet(currentInterfaces); final String className = compatBaseline.getClassName(); CoIterator iter = new CoIterator(JavaClassNameComparator.COMPARATOR, compat, current); while (iter.hasNext()) { iter.next(); JavaClass compatInterface = (JavaClass) iter.getLeft(); JavaClass currentInterface = (JavaClass) iter.getRight(); if (className.equals(compatInterface.getClassName()) || className.equals(currentInterface.getClassName())) { // This occurs because an interface has itself in the set of all interfaces. // We can't just let the test below handle this case because that won't // work when a gender change has occurred. continue; } if (compatInterface == null) ... [truncated message content]  |