diff options
Diffstat (limited to 'api/src/main/java/org')
8 files changed, 172 insertions, 51 deletions
diff --git a/api/src/main/java/org/osjava/jardiff/AbstractMemberInfo.java b/api/src/main/java/org/osjava/jardiff/AbstractMemberInfo.java new file mode 100644 index 0000000..4dc0ae9 --- /dev/null +++ b/api/src/main/java/org/osjava/jardiff/AbstractMemberInfo.java @@ -0,0 +1,25 @@ +package org.osjava.jardiff; + +public abstract class AbstractMemberInfo extends AbstractInfo { + + /** + * The internal name of this member's class + */ + private final String className; + + public AbstractMemberInfo(final String className, final int access, final String name) { + super(access, name); + this.className = className; + } + + /** + * Get the internal name of member's class + * + * @return the name + */ + public final String getClassName() { + return className; + } + + +} diff --git a/api/src/main/java/org/osjava/jardiff/ClassInfoVisitor.java b/api/src/main/java/org/osjava/jardiff/ClassInfoVisitor.java index be7d08b..7e91f58 100644 --- a/api/src/main/java/org/osjava/jardiff/ClassInfoVisitor.java +++ b/api/src/main/java/org/osjava/jardiff/ClassInfoVisitor.java @@ -24,7 +24,7 @@ import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** - * A reusable class which uses the ASM to build up ClassInfo about a + * A reusable class which uses the ASM to build up ClassInfo about a * java class file. * * @author <a href="mailto:[email protected]">Antony Riley</a> @@ -51,7 +51,7 @@ public class ClassInfoVisitor extends ClassVisitor * The signature of the class */ private String signature; - + /** * The internal name of the superclass. */ @@ -71,11 +71,11 @@ public class ClassInfoVisitor extends ClassVisitor * A map of field signature to a FieldInfo describing the field. */ private Map<String, FieldInfo> fieldMap; - + public ClassInfoVisitor() { super(Opcodes.ASM5); } - + /** * Reset this ClassInfoVisitor so that it can be used to visit another * class. @@ -84,7 +84,7 @@ public class ClassInfoVisitor extends ClassVisitor methodMap = new HashMap<String, MethodInfo>(); fieldMap = new HashMap<String, FieldInfo>(); } - + /** * The the classInfo this ClassInfoVisitor has built up about a class */ @@ -92,7 +92,7 @@ public class ClassInfoVisitor extends ClassVisitor return new ClassInfo(version, access, name, signature, supername, interfaces, methodMap, fieldMap); } - + /** * Receive notification of information about a class from ASM. * @@ -103,8 +103,8 @@ public class ClassInfoVisitor extends ClassVisitor * @param supername the internal name of the super class. * @param interfaces the internal names of interfaces implemented. */ - public void visit(int version, int access, String name, String signature, - String supername, String[] interfaces) { + public void visit(final int version, final int access, final String name, final String signature, + final String supername, final String[] interfaces) { this.version = version; this.access = access; this.name = name; @@ -114,18 +114,18 @@ public class ClassInfoVisitor extends ClassVisitor } @Override - public MethodVisitor visitMethod(int access, String name, String desc, - String signature, String[] exceptions) { - methodMap.put(name + desc, new MethodInfo(access, name, desc, + public MethodVisitor visitMethod(final int access, final String name, final String desc, + final String signature, final String[] exceptions) { + methodMap.put(name + desc, new MethodInfo(this.name, access, name, desc, signature, exceptions)); return null; } - + @Override - public FieldVisitor visitField(int access, String name, String desc, - String signature, Object value) { + public FieldVisitor visitField(final int access, final String name, final String desc, + final String signature, final Object value) { fieldMap.put(name, - new FieldInfo(access, name, desc, signature, value)); + new FieldInfo(this.name, access, name, desc, signature, value)); return null; } } diff --git a/api/src/main/java/org/osjava/jardiff/FieldInfo.java b/api/src/main/java/org/osjava/jardiff/FieldInfo.java index c159ba9..44bedd2 100644 --- a/api/src/main/java/org/osjava/jardiff/FieldInfo.java +++ b/api/src/main/java/org/osjava/jardiff/FieldInfo.java @@ -23,7 +23,7 @@ import java.util.Arrays; * * @author <a href="mailto:[email protected]">Antony Riley</a> */ -public final class FieldInfo extends AbstractInfo +public final class FieldInfo extends AbstractMemberInfo { /** * The field descriptor for this field. @@ -43,15 +43,16 @@ public final class FieldInfo extends AbstractInfo /** * Create a new FieldInfo * + * @param className The name of the class this field belongs to * @param access The access flags. * @param name The name of the field. * @param desc The field descriptor. * @param signature The signature of this field. * @param value The initial value of the field. */ - public FieldInfo(final int access, final String name, final String desc, final String signature, + public FieldInfo(final String className, final int access, final String name, final String desc, final String signature, final Object value) { - super(access, name); + super(className, access, name); this.desc = desc; this.signature = signature; this.value = value; diff --git a/api/src/main/java/org/osjava/jardiff/JarDiff.java b/api/src/main/java/org/osjava/jardiff/JarDiff.java index f32982c..1b20cb7 100644 --- a/api/src/main/java/org/osjava/jardiff/JarDiff.java +++ b/api/src/main/java/org/osjava/jardiff/JarDiff.java @@ -356,40 +356,81 @@ public class JarDiff final Map<String, MethodInfo> extNewMethods = new HashMap<String, MethodInfo>(newMethods); final Map<String, FieldInfo> extNewFields = new HashMap<String, FieldInfo>(newFields); - String superClass = nci.getSupername(); - while (superClass != null && newClassInfo.containsKey(superClass)) { - final ClassInfo sci = newClassInfo.get(superClass); - for (final Map.Entry<String, FieldInfo> entry : sci.getFieldMap().entrySet()) { - if (!(entry.getValue()).isPrivate() - && !extNewFields.containsKey(entry.getKey())) { - extNewFields.put(entry.getKey(), entry.getValue()); + // For all super classes + // - Moving methods upward is OK! + // - static final fields are resolved at compile time! + { + String superClass = nci.getSupername(); + ClassInfo sci; + while ( superClass != null && null != ( sci = newClassInfo.get(superClass) ) ) { + for (final Map.Entry<String, FieldInfo> entry : sci.getFieldMap().entrySet()) { + if ( !entry.getValue().isPrivate() && + !extNewFields.containsKey(entry.getKey()) ) { + extNewFields.put(entry.getKey(), entry.getValue()); + } } + for (final Map.Entry<String, MethodInfo> entry : sci.getMethodMap().entrySet()) { + if ( !entry.getValue().isPrivate() && + !extNewMethods.containsKey(entry.getKey()) ) { + extNewMethods.put(entry.getKey(), entry.getValue()); + } + } + superClass = sci.getSupername(); } - for (final Map.Entry<String, MethodInfo> entry : sci.getMethodMap().entrySet()) { - if (!(entry.getValue()).isPrivate() - && !extNewMethods.containsKey(entry.getKey())) { - extNewMethods.put(entry.getKey(), entry.getValue()); + } + // For all super interfaces + // - Moving methods upward is OK! + // - static final fields are resolved at compile time! + { + final ArrayList<String> superInterfaces = new ArrayList<String>(Arrays.asList(nci.getInterfaces())); + final Set<String> done = new HashSet<String>(); + for(int i=0; i<superInterfaces.size(); i++) { + final String superFace = superInterfaces.get(i); + if( null != superFace && !done.contains(superFace) ) { + done.add(superFace); + final ClassInfo sii; + if( null != ( sii = newClassInfo.get(superFace) ) ) { + for (final Map.Entry<String, FieldInfo> entry : sii.getFieldMap().entrySet()) { + if ( !entry.getValue().isPrivate() && + !extNewFields.containsKey(entry.getKey()) ) { + extNewFields.put(entry.getKey(), entry.getValue()); + } + } + for (final Map.Entry<String, MethodInfo> entry : sii.getMethodMap().entrySet()) { + if ( !entry.getValue().isPrivate() && + !extNewMethods.containsKey(entry.getKey()) ) { + extNewMethods.put(entry.getKey(), entry.getValue()); + } + } + // Append this ssi's super interfaces in a unique manner + final List<String> ssi = new ArrayList<String>(Arrays.asList(sii.getInterfaces())); + ssi.removeAll(superInterfaces); + superInterfaces.addAll(ssi); + } } } - superClass = sci.getSupername(); } for (final Map.Entry<String, MethodInfo> entry : oldMethods.entrySet()) { - if (criteria.validMethod(entry.getValue())) + if (criteria.validMethod(entry.getValue())) { removedMethods.add(entry.getKey()); + } } for (final Map.Entry<String, FieldInfo> entry : oldFields.entrySet()) { - if (criteria.validField(entry.getValue())) + if (criteria.validField(entry.getValue())) { removedFields.add(entry.getKey()); + } } for (final Map.Entry<String, MethodInfo> entry : newMethods.entrySet()) { - if (criteria.validMethod(entry.getValue())) + if (criteria.validMethod(entry.getValue())) { addedMethods.add(entry.getKey()); + } } for (final Map.Entry<String, FieldInfo> entry : newFields.entrySet()) { - if (criteria.validField(entry.getValue())) + if (criteria.validField(entry.getValue())) { addedFields.add(entry.getKey()); + } } // We add all the old methods that match the criteria @@ -397,12 +438,13 @@ public class JarDiff // We keep the intersection of these with all the new methods // to detect as changed a method that no longer match the // criteria (i.e. a method that was public and is now private) - changedMethods.retainAll(newMethods.keySet()); + changedMethods.retainAll(extNewMethods.keySet()); removedMethods.removeAll(changedMethods); removedMethods.removeAll(extNewMethods.keySet()); addedMethods.removeAll(changedMethods); + changedFields.addAll(removedFields); - changedFields.retainAll(newFields.keySet()); + changedFields.retainAll(extNewFields.keySet()); removedFields.removeAll(changedFields); removedFields.removeAll(extNewFields.keySet()); addedFields.removeAll(changedFields); @@ -411,7 +453,7 @@ public class JarDiff while (j.hasNext()) { final String desc = j.next(); final MethodInfo oldInfo = oldMethods.get(desc); - final MethodInfo newInfo = newMethods.get(desc); + final MethodInfo newInfo = extNewMethods.get(desc); if (!criteria.differs(oldInfo, newInfo)) { j.remove(); } @@ -420,7 +462,7 @@ public class JarDiff while (j.hasNext()) { final String desc = j.next(); final FieldInfo oldInfo = oldFields.get(desc); - final FieldInfo newInfo = newFields.get(desc); + final FieldInfo newInfo = extNewFields.get(desc); if (!criteria.differs(oldInfo, newInfo)) { j.remove(); } @@ -464,7 +506,7 @@ public class JarDiff for (final String field : changedFields) { final FieldInfo oldFieldInfo = oldFields.get(field); - final FieldInfo newFieldInfo = newFields.get(field); + final FieldInfo newFieldInfo = extNewFields.get(field); // Was only deprecated? if (wasDeprecated(oldFieldInfo, newFieldInfo) && !criteria.differs(cloneDeprecated(oldFieldInfo), newFieldInfo)) { @@ -477,7 +519,7 @@ public class JarDiff } for (final String method : changedMethods) { final MethodInfo oldMethodInfo = oldMethods.get(method); - final MethodInfo newMethodInfo = newMethods.get(method); + final MethodInfo newMethodInfo = extNewMethods.get(method); // Was only deprecated? if (wasDeprecated(oldMethodInfo, newMethodInfo) && !criteria.differs(cloneDeprecated(oldMethodInfo), newMethodInfo)) { @@ -537,7 +579,7 @@ public class JarDiff * @return the cloned and deprecated method info. */ private static MethodInfo cloneDeprecated(final MethodInfo methodInfo) { - return new MethodInfo(methodInfo.getAccess() | Opcodes.ACC_DEPRECATED, + return new MethodInfo(methodInfo.getClassName(), methodInfo.getAccess() | Opcodes.ACC_DEPRECATED, methodInfo.getName(), methodInfo.getDesc(), methodInfo.getSignature(), methodInfo.getExceptions()); } @@ -550,7 +592,7 @@ public class JarDiff * @return the cloned and deprecated field info. */ private static FieldInfo cloneDeprecated(final FieldInfo fieldInfo) { - return new FieldInfo(fieldInfo.getAccess() | Opcodes.ACC_DEPRECATED, + return new FieldInfo(fieldInfo.getClassName(), fieldInfo.getAccess() | Opcodes.ACC_DEPRECATED, fieldInfo.getName(), fieldInfo.getDesc(), fieldInfo.getSignature(), fieldInfo.getValue()); } diff --git a/api/src/main/java/org/osjava/jardiff/MethodInfo.java b/api/src/main/java/org/osjava/jardiff/MethodInfo.java index 797faa4..32f7b06 100644 --- a/api/src/main/java/org/osjava/jardiff/MethodInfo.java +++ b/api/src/main/java/org/osjava/jardiff/MethodInfo.java @@ -23,7 +23,7 @@ import java.util.Arrays; * * @author <a href="mailto:[email protected]">Antony Riley</a> */ -public final class MethodInfo extends AbstractInfo +public final class MethodInfo extends AbstractMemberInfo { /** * The method descriptor. @@ -43,14 +43,15 @@ public final class MethodInfo extends AbstractInfo /** * Create a new MethodInfo with the specified parameters. * + * @param className The name of the class this method belongs to * @param access The access flags for the method. * @param name The name of the method. * @param signature The signature of the method. * @param exceptions The exceptions thrown by the method. */ - public MethodInfo(final int access, final String name, final String desc, final String signature, + public MethodInfo(final String className, final int access, final String name, final String desc, final String signature, final String[] exceptions) { - super(access, name); + super(className, access, name); this.desc = desc; this.signature = signature; this.exceptions = exceptions; diff --git a/api/src/main/java/org/osjava/jardiff/PublicDiffCriteria.java b/api/src/main/java/org/osjava/jardiff/PublicDiffCriteria.java index c5e2f02..54a33cc 100644 --- a/api/src/main/java/org/osjava/jardiff/PublicDiffCriteria.java +++ b/api/src/main/java/org/osjava/jardiff/PublicDiffCriteria.java @@ -28,6 +28,15 @@ import java.util.Set; */ public class PublicDiffCriteria implements DiffCriteria { + final boolean ignoreClassName; + + public PublicDiffCriteria() { + this.ignoreClassName = false; + } + public PublicDiffCriteria(final boolean ignoreClassName) { + this.ignoreClassName = ignoreClassName; + } + @Override public boolean equals(final Object arg) { if (arg == this) { @@ -104,7 +113,8 @@ public class PublicDiffCriteria implements DiffCriteria @Override public boolean differs(final MethodInfo oldInfo, final MethodInfo newInfo) { - return // Tools.isDescChange(oldInfo.getDesc(), newInfo.getDesc()) || + return !ignoreClassName && !oldInfo.getClassName().equals(newInfo.getClassName()) || + // Tools.isDescChange(oldInfo.getDesc(), newInfo.getDesc()) || Tools.isMethodAccessChange(oldInfo.getAccess(), newInfo.getAccess()) || Tools.isThrowsClauseChange(oldInfo.getExceptions(), newInfo.getExceptions()); } @@ -116,7 +126,8 @@ public class PublicDiffCriteria implements DiffCriteria @Override public boolean differs(final FieldInfo oldInfo, final FieldInfo newInfo) { - return Tools.isFieldTypeChange(oldInfo.getValue(), newInfo.getValue()) || + return !ignoreClassName && !oldInfo.getClassName().equals(newInfo.getClassName()) || + Tools.isFieldTypeChange(oldInfo.getValue(), newInfo.getValue()) || Tools.isFieldAccessChange(oldInfo.getAccess(), newInfo.getAccess()) || Tools.isFieldValueChange(oldInfo.getValue(), newInfo.getValue()); } diff --git a/api/src/main/java/org/osjava/jardiff/SimpleDiffCriteria.java b/api/src/main/java/org/osjava/jardiff/SimpleDiffCriteria.java index 09d1108..d9d47d0 100644 --- a/api/src/main/java/org/osjava/jardiff/SimpleDiffCriteria.java +++ b/api/src/main/java/org/osjava/jardiff/SimpleDiffCriteria.java @@ -28,6 +28,15 @@ import java.util.Set; */ public class SimpleDiffCriteria implements DiffCriteria { + final boolean ignoreClassName; + + public SimpleDiffCriteria() { + this.ignoreClassName = false; + } + public SimpleDiffCriteria(final boolean ignoreClassName) { + this.ignoreClassName = ignoreClassName; + } + @Override public boolean equals(final Object arg) { if (arg == this) { @@ -104,7 +113,8 @@ public class SimpleDiffCriteria implements DiffCriteria @Override public boolean differs(final MethodInfo oldInfo, final MethodInfo newInfo) { - return // Tools.isDescChange(oldInfo.getDesc(), newInfo.getDesc()) || + return !ignoreClassName && !oldInfo.getClassName().equals(newInfo.getClassName()) || + // Tools.isDescChange(oldInfo.getDesc(), newInfo.getDesc()) || Tools.isMethodAccessChange(oldInfo.getAccess(), newInfo.getAccess()) || Tools.isThrowsClauseChange(oldInfo.getExceptions(), newInfo.getExceptions()); } @@ -116,7 +126,8 @@ public class SimpleDiffCriteria implements DiffCriteria @Override public boolean differs(final FieldInfo oldInfo, final FieldInfo newInfo) { - return Tools.isFieldTypeChange(oldInfo.getValue(), newInfo.getValue()) || + return !ignoreClassName && !oldInfo.getClassName().equals(newInfo.getClassName()) || + Tools.isFieldTypeChange(oldInfo.getValue(), newInfo.getValue()) || Tools.isFieldAccessChange(oldInfo.getAccess(), newInfo.getAccess()) || Tools.isFieldValueChange(oldInfo.getValue(), newInfo.getValue()); } diff --git a/api/src/main/java/org/semver/Dumper.java b/api/src/main/java/org/semver/Dumper.java index 30824f5..0e628e0 100755 --- a/api/src/main/java/org/semver/Dumper.java +++ b/api/src/main/java/org/semver/Dumper.java @@ -29,6 +29,7 @@ import java.util.Map; import java.util.Set; import org.osjava.jardiff.AbstractInfo; +import org.osjava.jardiff.AbstractMemberInfo; import org.osjava.jardiff.ClassInfo; import org.osjava.jardiff.FieldInfo; import org.osjava.jardiff.MethodInfo; @@ -76,10 +77,39 @@ public class Dumper { return builder.toString(); } + private static int findCommonPrefix(final String strA, final String strB, final char c) { + int i = 0; + int lastC = -1; + final int end = Math.min(strA.length(), strB.length()); + for (; i < end; i++) { + final char strAc = strA.charAt(i); + if (strAc != strB.charAt(i)) { + break; + } else if( 0 < c && strAc == c ) { + lastC = i; + } + } + return lastC >= 0 ? lastC+1 : i; + } + + protected static StringBuilder appendNameChangeDetails(final StringBuilder builder, final AbstractInfo previousInfo, final AbstractInfo currentInfo) { + if( previousInfo instanceof AbstractMemberInfo && currentInfo instanceof AbstractMemberInfo ) { + final String preClz = ((AbstractMemberInfo)previousInfo).getClassName().replace('/', '.'); + final String curClz = ((AbstractMemberInfo)currentInfo).getClassName().replace('/', '.'); + final int prefixIdx = findCommonPrefix(preClz, curClz, '.'); + final String common = preClz.substring(0, prefixIdx); + if( !preClz.equals(curClz) ) { + builder.append(common+"["+preClz.substring(prefixIdx, preClz.length())+" -> "+curClz.substring(prefixIdx, curClz.length())+"]."); + } + } + builder.append(previousInfo.getName()); + return builder; + } + protected static String extractChangeDetails(final AbstractInfo previousInfo, final AbstractInfo currentInfo) { final StringBuilder builder = new StringBuilder(); if (!(previousInfo instanceof ClassInfo)) { - builder.append(previousInfo.getName()); + appendNameChangeDetails(builder, previousInfo, currentInfo); final String pSig = previousInfo.getSignature(); final String pDesc = previousInfo.getDesc(); final String cSig = currentInfo.getSignature(); @@ -112,7 +142,7 @@ public class Dumper { protected static String extractCompatChangeDetails(final AbstractInfo previousInfo, final AbstractInfo currentInfo) { final StringBuilder builder = new StringBuilder(); if (!(previousInfo instanceof ClassInfo)) { - builder.append(previousInfo.getName()); + appendNameChangeDetails(builder, previousInfo, currentInfo); } if( previousInfo instanceof MethodInfo ) { final MethodInfo mPreInfo = (MethodInfo)previousInfo; |