Skip to content

Commit

Permalink
#119 interface is no longer reported as removed if it gets implemente…
Browse files Browse the repository at this point in the history
…d by a new interface hierarchy
  • Loading branch information
siom79 committed Mar 14, 2016
1 parent 4c5d562 commit df77875
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 7 deletions.
23 changes: 18 additions & 5 deletions japicmp/src/main/java/japicmp/model/JApiClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,8 @@ private void computeInterfaceChanges(List<JApiImplementedInterface> interfacesAr
if (oldClassOptional.isPresent() && newClassOptional.isPresent()) {
CtClass oldClass = oldClassOptional.get();
CtClass newClass = newClassOptional.get();
Map<String, CtClass> interfaceMapOldClass = buildInterfaceMap(oldClass);
Map<String, CtClass> interfaceMapNewClass = buildInterfaceMap(newClass);
Map<String, CtClass> interfaceMapOldClass = buildInterfaceMap(oldClass, JarArchiveComparator.ArchiveType.OLD);
Map<String, CtClass> interfaceMapNewClass = buildInterfaceMap(newClass, JarArchiveComparator.ArchiveType.NEW);
for (CtClass oldInterface : interfaceMapOldClass.values()) {
CtClass ctClassFound = interfaceMapNewClass.get(oldInterface.getName());
if (ctClassFound != null) {
Expand All @@ -255,13 +255,13 @@ private void computeInterfaceChanges(List<JApiImplementedInterface> interfacesAr
}
} else {
if (oldClassOptional.isPresent()) {
Map<String, CtClass> interfaceMap = buildInterfaceMap(oldClassOptional.get());
Map<String, CtClass> interfaceMap = buildInterfaceMap(oldClassOptional.get(), JarArchiveComparator.ArchiveType.OLD);
for (CtClass ctClass : interfaceMap.values()) {
JApiImplementedInterface jApiClass = new JApiImplementedInterface(ctClass.getName(), JApiChangeStatus.REMOVED);
interfacesArg.add(jApiClass);
}
} else if (newClassOptional.isPresent()) {
Map<String, CtClass> interfaceMap = buildInterfaceMap(newClassOptional.get());
Map<String, CtClass> interfaceMap = buildInterfaceMap(newClassOptional.get(), JarArchiveComparator.ArchiveType.NEW);
for (CtClass ctClass : interfaceMap.values()) {
JApiImplementedInterface jApiClass = new JApiImplementedInterface(ctClass.getName(), JApiChangeStatus.NEW);
interfacesArg.add(jApiClass);
Expand All @@ -270,12 +270,13 @@ private void computeInterfaceChanges(List<JApiImplementedInterface> interfacesAr
}
}

private Map<String, CtClass> buildInterfaceMap(CtClass ctClass) {
private Map<String, CtClass> buildInterfaceMap(CtClass ctClass, JarArchiveComparator.ArchiveType archiveType) {
Map<String, CtClass> map = new HashMap<>();
try {
CtClass[] interfaces = ctClass.getInterfaces();
for (CtClass ctInterface : interfaces) {
map.put(ctInterface.getName(), ctInterface);
buildInterfaceMap(archiveType, map, ctInterface);
}
} catch (NotFoundException e) {
if (!options.isIgnoreMissingClasses()) {
Expand All @@ -285,6 +286,18 @@ private Map<String, CtClass> buildInterfaceMap(CtClass ctClass) {
return map;
}

private void buildInterfaceMap(JarArchiveComparator.ArchiveType archiveType, Map<String, CtClass> map, CtClass ctInterface) throws NotFoundException {
Optional<CtClass> loadedInterfaceOptional = this.jarArchiveComparator.loadClass(archiveType, ctInterface.getName());
if (loadedInterfaceOptional.isPresent()) {
CtClass loadedInterface = loadedInterfaceOptional.get();
CtClass[] loadedInterfaceInterfaces = loadedInterface.getInterfaces();
for (CtClass additionalInterface : loadedInterfaceInterfaces) {
map.put(additionalInterface.getName(), additionalInterface);
buildInterfaceMap(archiveType, map, additionalInterface);
}
}
}

private void computeMethodChanges(JApiClass jApiClass, Optional<CtClass> oldClassOptional, Optional<CtClass> newClassOptional) {
Map<String, List<CtMethod>> oldMethodsMap = createMethodMap(oldClassOptional);
Map<String, List<CtMethod>> newMethodsMap = createMethodMap(newClassOptional);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ private JApiJavaObjectSerializationCompatibility.JApiJavaObjectSerializationChan
private JApiJavaObjectSerializationCompatibility.JApiJavaObjectSerializationChangeStatus checkChangesForInterfaces(JApiClass jApiClass, JApiJavaObjectSerializationCompatibility.JApiJavaObjectSerializationChangeStatus state) {
boolean serializableAdded = false;
boolean serializableRemoved = false;
boolean serializableUnchanged = false;
boolean externalizableAdded = false;
boolean externalizableRemoved = false;
for (JApiImplementedInterface implementedInterface : jApiClass.getInterfaces()) {
Expand All @@ -225,6 +226,8 @@ private JApiJavaObjectSerializationCompatibility.JApiJavaObjectSerializationChan
serializableAdded = true;
} else if (implementedInterface.getChangeStatus() == JApiChangeStatus.REMOVED) {
serializableRemoved = true;
} else if (implementedInterface.getChangeStatus() == JApiChangeStatus.UNCHANGED) {
serializableUnchanged = true;
}
}
if (Externalizable.class.getCanonicalName().equals(implementedInterface.getFullyQualifiedName())) {
Expand All @@ -241,10 +244,10 @@ private JApiJavaObjectSerializationCompatibility.JApiJavaObjectSerializationChan
if (externalizableRemoved) {
state = JApiJavaObjectSerializationCompatibility.JApiJavaObjectSerializationChangeStatus.SERIALIZABLE_INCOMPATIBLE_EXTERNALIZABLE_REMOVED;
}
if (serializableRemoved && externalizableAdded) {
if ((serializableRemoved || serializableUnchanged || serializableAdded) && externalizableAdded) {
state = JApiJavaObjectSerializationCompatibility.JApiJavaObjectSerializationChangeStatus.SERIALIZABLE_INCOMPATIBLE_CHANGED_FROM_SERIALIZABLE_TO_EXTERNALIZABLE;
}
if (serializableAdded && externalizableRemoved) {
if ((serializableUnchanged || serializableAdded) && externalizableRemoved) {
state = JApiJavaObjectSerializationCompatibility.JApiJavaObjectSerializationChangeStatus.SERIALIZABLE_INCOMPATIBLE_CHANGED_FROM_EXTERNALIZABLE_TO_SERIALIZABLE;
}
return state;
Expand Down
29 changes: 29 additions & 0 deletions japicmp/src/test/java/japicmp/cmp/InterfacesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.List;

import static japicmp.util.Helper.getJApiClass;
import static japicmp.util.Helper.getJApiImplementedInterface;
import static japicmp.util.Helper.getJApiMethod;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.CoreMatchers.is;
Expand Down Expand Up @@ -184,4 +185,32 @@ public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
assertThat(jApiClass.isBinaryCompatible(), is(true));
assertThat(jApiClass.isSourceCompatible(), is(true));
}

@Test
public void testInterfaceHierarchyHasOneMoreLevel() throws Exception {
JarArchiveComparatorOptions jarArchiveComparatorOptions = new JarArchiveComparatorOptions();
jarArchiveComparatorOptions.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(jarArchiveComparatorOptions, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClassInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().name("Test").implementsInterface(ctClassInterface).addToClassPool(classPool);
return Arrays.asList(ctClassInterface, ctClass);
}

@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClassInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool);
CtClass ctClassSubInterface = CtInterfaceBuilder.create().name("SubInterface").withSuperInterface(ctClassInterface).addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().name("Test").implementsInterface(ctClassSubInterface).addToClassPool(classPool);
return Arrays.asList(ctClassInterface, ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "Test");
assertThat(jApiClass.isBinaryCompatible(), is(true));
assertThat(jApiClass.isSourceCompatible(), is(true));
assertThat(jApiClass.getInterfaces().size(), is(2));
assertThat(getJApiImplementedInterface(jApiClass.getInterfaces(), "Interface").getChangeStatus(), is(JApiChangeStatus.UNCHANGED));
assertThat(getJApiImplementedInterface(jApiClass.getInterfaces(), "SubInterface").getChangeStatus(), is(JApiChangeStatus.NEW));
}
}

0 comments on commit df77875

Please sign in to comment.