Skip to content

Commit

Permalink
#59: added compatibility change METHOD_ADDED_TO_INTERFACE
Browse files Browse the repository at this point in the history
  • Loading branch information
siom79 committed Jan 19, 2016
1 parent 8cb9079 commit 35f95ed
Showing 13 changed files with 178 additions and 17 deletions.
11 changes: 10 additions & 1 deletion japicmp/src/main/java/japicmp/compat/CompatibilityChanges.java
Original file line number Diff line number Diff line change
@@ -265,9 +265,18 @@ public int callback(JApiClass superclass, Map<String, JApiClass> classMap) {
addCompatibilityChange(method, JApiCompatibilityChange.METHOD_NO_LONGER_STATIC);
}
}
if (isInterface(jApiClass)) {
if (method.getChangeStatus() == JApiChangeStatus.NEW) {
addCompatibilityChange(method, JApiCompatibilityChange.METHOD_ADDED_TO_INTERFACE);
}
}
}
}

private boolean isInterface(JApiClass jApiClass) {
return jApiClass.getClassType().getNewTypeOptional().isPresent() && jApiClass.getClassType().getNewTypeOptional().get() == JApiClassType.ClassType.INTERFACE;
}

private void checkIfMethodHasBeenPulledUp(JApiClass jApiClass, Map<String, JApiClass> classMap, final JApiMethod method, List<Integer> returnValues) {
JApiClassType classType = jApiClass.getClassType();
Optional<JApiClassType.ClassType> newTypeOptional = classType.getNewTypeOptional();
@@ -373,7 +382,7 @@ public int callback(JApiClass superclass, Map<String, JApiClass> classMap) {
}
}

private void addCompatibilityChange(JApiBinaryCompatibility binaryCompatibility, JApiCompatibilityChange compatibilityChange) {
private void addCompatibilityChange(JApiCompatibility binaryCompatibility, JApiCompatibilityChange compatibilityChange) {
List<JApiCompatibilityChange> compatibilityChanges = binaryCompatibility.getCompatibilityChanges();
if (!compatibilityChanges.contains(compatibilityChange)) {
compatibilityChanges.add(compatibilityChange);
8 changes: 7 additions & 1 deletion japicmp/src/main/java/japicmp/model/JApiAnnotation.java
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@
import javax.xml.bind.annotation.XmlTransient;
import java.util.*;

public class JApiAnnotation implements JApiHasChangeStatus, JApiBinaryCompatibility {
public class JApiAnnotation implements JApiHasChangeStatus, JApiCompatibility {
private final String fullyQualifiedName;
private final Optional<Annotation> oldAnnotation;
private final Optional<Annotation> newAnnotation;
@@ -134,6 +134,12 @@ public boolean isBinaryCompatible() {
return true;
}

@Override
@XmlAttribute
public boolean isSourceCompatible() {
return true;
}

@XmlElementWrapper(name = "compatibilityChanges")
@XmlElement(name = "compatibilityChange")
public List<JApiCompatibilityChange> getCompatibilityChanges() {
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@
import java.util.Collections;
import java.util.List;

public class JApiAnnotationElement implements JApiHasChangeStatus, JApiBinaryCompatibility {
public class JApiAnnotationElement implements JApiHasChangeStatus, JApiCompatibility {
private final String name;
private final Optional<MemberValue> oldValue;
private final Optional<MemberValue> newValue;
@@ -150,6 +150,11 @@ public boolean isBinaryCompatible() {
return true;
}

@XmlAttribute
public boolean isSourceCompatible() {
return true;
}

@XmlElementWrapper(name = "compatibilityChanges")
@XmlElement(name = "compatibilityChange")
public List getCompatibilityChanges() {
14 changes: 13 additions & 1 deletion japicmp/src/main/java/japicmp/model/JApiBehavior.java
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@
import java.util.List;

public class JApiBehavior implements JApiHasModifiers, JApiHasChangeStatus, JApiHasAccessModifier, JApiHasStaticModifier,
JApiHasFinalModifier, JApiHasAbstractModifier, JApiBinaryCompatibility, JApiHasAnnotations, JApiHasBridgeModifier,
JApiHasFinalModifier, JApiHasAbstractModifier, JApiCompatibility, JApiHasAnnotations, JApiHasBridgeModifier,
JApiCanBeSynthetic, JApiHasLineNumber {
private final String name;
private final List<JApiParameter> parameters = new LinkedList<>();
@@ -344,6 +344,18 @@ public boolean isBinaryCompatible() {
return binaryCompatible;
}

@Override
@XmlAttribute
public boolean isSourceCompatible() {
boolean sourceCompatible = true;
for (JApiCompatibilityChange compatibilityChange : compatibilityChanges) {
if (!compatibilityChange.isSourceCompatible()) {
sourceCompatible = false;
}
}
return sourceCompatible;
}

@XmlElementWrapper(name = "compatibilityChanges")
@XmlElement(name = "compatibilityChange")
public List<JApiCompatibilityChange> getCompatibilityChanges() {
47 changes: 46 additions & 1 deletion japicmp/src/main/java/japicmp/model/JApiClass.java
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@
import java.util.*;

public class JApiClass implements JApiHasModifiers, JApiHasChangeStatus, JApiHasAccessModifier, JApiHasStaticModifier, JApiHasFinalModifier, JApiHasAbstractModifier,
JApiBinaryCompatibility, JApiHasAnnotations, JApiJavaObjectSerializationCompatibility, JApiCanBeSynthetic {
JApiCompatibility, JApiHasAnnotations, JApiJavaObjectSerializationCompatibility, JApiCanBeSynthetic {
private final JarArchiveComparator jarArchiveComparator;
private final String fullyQualifiedName;
private final JApiClassType classType;
@@ -771,6 +771,51 @@ public boolean isBinaryCompatible() {
return binaryCompatible;
}

@Override
@XmlAttribute
public boolean isSourceCompatible() {
boolean sourceCompatible = true;
for (JApiCompatibilityChange compatibilityChange : compatibilityChanges) {
if (!compatibilityChange.isSourceCompatible()) {
sourceCompatible = false;
break;
}
}
if (sourceCompatible) {
for (JApiField field : fields) {
if (!field.isSourceCompatible()) {
sourceCompatible = false;
break;
}
}
}
if (sourceCompatible) {
for (JApiMethod method : methods) {
if (!method.isSourceCompatible()) {
sourceCompatible = false;
break;
}
}
}
if (sourceCompatible) {
for (JApiConstructor constructor : constructors) {
if (!constructor.isSourceCompatible()) {
sourceCompatible = false;
break;
}
}
}
if (sourceCompatible) {
for (JApiImplementedInterface implementedInterface : interfaces) {
if (!implementedInterface.isSourceCompatible()) {
sourceCompatible = false;
break;
}
}
}
return sourceCompatible;
}

@XmlElementWrapper(name = "annotations")
@XmlElement(name = "annotation")
public List<JApiAnnotation> getAnnotations() {
Original file line number Diff line number Diff line change
@@ -3,15 +3,23 @@
import java.util.List;

/**
* Implemented by elements which can indicate if they have changed binary compatible or not.
* Implemented by elements which can indicate if they have changed compatible or not.
*/
public interface JApiBinaryCompatibility {
public interface JApiCompatibility {
/**
* Returns true if this element has changed binary compatible.
*
* @return true if this element has changed binary compatible
*/
boolean isBinaryCompatible();

/**
* Returns true if this element has changed source compatible.
*
* @return true if this element has changed source compatible
*/
boolean isSourceCompatible();

/**
* Returns all compatibility changes.
* @return a list of compatibility changes
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ public enum JApiCompatibilityChange {
METHOD_NOW_FINAL(false, false),
METHOD_NOW_STATIC(false, false),
METHOD_NO_LONGER_STATIC(false, false),
METHOD_ADDED_TO_INTERFACE(true, false),
FIELD_STATIC_AND_OVERRIDES_STATIC(false, false),
FIELD_LESS_ACCESSIBLE_THAN_IN_SUPERCLASS(false, false),
FIELD_NOW_FINAL(false, false),
14 changes: 13 additions & 1 deletion japicmp/src/main/java/japicmp/model/JApiField.java
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@
import java.util.List;

public class JApiField implements JApiHasChangeStatus, JApiHasModifiers, JApiHasAccessModifier, JApiHasStaticModifier,
JApiHasFinalModifier, JApiHasTransientModifier, JApiBinaryCompatibility, JApiHasAnnotations, JApiCanBeSynthetic {
JApiHasFinalModifier, JApiHasTransientModifier, JApiCompatibility, JApiHasAnnotations, JApiCanBeSynthetic {
private final JApiChangeStatus changeStatus;
private final Optional<CtField> oldFieldOptional;
private final Optional<CtField> newFieldOptional;
@@ -327,6 +327,18 @@ public boolean isBinaryCompatible() {
return binaryCompatible;
}

@Override
@XmlAttribute
public boolean isSourceCompatible() {
boolean sourceCompatible = true;
for (JApiCompatibilityChange compatibilityChange : compatibilityChanges) {
if (!compatibilityChange.isSourceCompatible()) {
sourceCompatible = false;
}
}
return sourceCompatible;
}

@XmlElementWrapper(name = "compatibilityChanges")
@XmlElement(name = "compatibilityChange")
public List<JApiCompatibilityChange> getCompatibilityChanges() {
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@
import java.util.ArrayList;
import java.util.List;

public class JApiImplementedInterface implements JApiHasChangeStatus, JApiBinaryCompatibility {
public class JApiImplementedInterface implements JApiHasChangeStatus, JApiCompatibility {
private final String fullyQualifiedName;
private final JApiChangeStatus changeStatus;
private final List<JApiCompatibilityChange> compatibilityChanges = new ArrayList<>();
@@ -46,6 +46,23 @@ public boolean isBinaryCompatible() {
return binaryCompatible;
}

@Override
@XmlAttribute
public boolean isSourceCompatible() {
boolean sourceCompatible = true;
for (JApiCompatibilityChange compatibilityChange : compatibilityChanges) {
if (!compatibilityChange.isSourceCompatible()) {
sourceCompatible = false;
}
}
if (sourceCompatible && correspondingJApiClass.isPresent()) {
if (!correspondingJApiClass.get().isSourceCompatible()) {
sourceCompatible = false;
}
}
return sourceCompatible;
}

@XmlElementWrapper(name = "compatibilityChanges")
@XmlElement(name = "compatibilityChange")
public List<JApiCompatibilityChange> getCompatibilityChanges() {
19 changes: 18 additions & 1 deletion japicmp/src/main/java/japicmp/model/JApiSuperclass.java
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
import java.util.LinkedList;
import java.util.List;

public class JApiSuperclass implements JApiHasChangeStatus, JApiBinaryCompatibility {
public class JApiSuperclass implements JApiHasChangeStatus, JApiCompatibility {
private final Optional<CtClass> oldSuperclassOptional;
private final Optional<CtClass> newSuperclassOptional;
private final JApiChangeStatus changeStatus;
@@ -115,6 +115,23 @@ public boolean isBinaryCompatible() {
return binaryCompatible;
}

@Override
@XmlAttribute
public boolean isSourceCompatible() {
boolean sourceCompatible = true;
for (JApiCompatibilityChange compatibilityChange : compatibilityChanges) {
if (!compatibilityChange.isSourceCompatible()) {
sourceCompatible = false;
}
}
if (sourceCompatible && correspondingJApiClass.isPresent()) {
if (!correspondingJApiClass.get().isSourceCompatible()) {
sourceCompatible = false;
}
}
return sourceCompatible;
}

@XmlElementWrapper(name = "compatibilityChanges")
@XmlElement(name = "compatibilityChange")
public List<JApiCompatibilityChange> getCompatibilityChanges() {
6 changes: 3 additions & 3 deletions japicmp/src/main/java/japicmp/output/semver/SemverOut.java
Original file line number Diff line number Diff line change
@@ -79,8 +79,8 @@ private SemverStatus signs(JApiHasChangeStatus hasChangeStatus) {
case NEW:
case REMOVED:
case MODIFIED:
if (hasChangeStatus instanceof JApiBinaryCompatibility) {
JApiBinaryCompatibility binaryCompatibility = (JApiBinaryCompatibility) hasChangeStatus;
if (hasChangeStatus instanceof JApiCompatibility) {
JApiCompatibility binaryCompatibility = (JApiCompatibility) hasChangeStatus;
if (binaryCompatibility.isBinaryCompatible()) {
if (hasChangeStatus instanceof JApiHasAccessModifier) {
JApiHasAccessModifier jApiHasAccessModifier = (JApiHasAccessModifier) hasChangeStatus;
@@ -113,7 +113,7 @@ private SemverStatus signs(JApiHasChangeStatus hasChangeStatus) {
}
}
} else {
throw new IllegalStateException("Element '" + hasChangeStatus.getClass().getCanonicalName() + " does not implement '" + JApiBinaryCompatibility.class.getCanonicalName() + "'.");
throw new IllegalStateException("Element '" + hasChangeStatus.getClass().getCanonicalName() + " does not implement '" + JApiCompatibility.class.getCanonicalName() + "'.");
}
default:
throw new IllegalStateException("The following JApiChangeStatus is not supported: " + (changeStatus == null ? "null" : changeStatus.name()));
Original file line number Diff line number Diff line change
@@ -109,8 +109,8 @@ private String signs(JApiHasChangeStatus hasChangeStatus) {
break;
}
boolean binaryCompatible = true;
if (hasChangeStatus instanceof JApiBinaryCompatibility) {
JApiBinaryCompatibility binaryCompatibility = (JApiBinaryCompatibility) hasChangeStatus;
if (hasChangeStatus instanceof JApiCompatibility) {
JApiCompatibility binaryCompatibility = (JApiCompatibility) hasChangeStatus;
binaryCompatible = binaryCompatibility.isBinaryCompatible();
}
if (binaryCompatible) {
33 changes: 31 additions & 2 deletions japicmp/src/test/java/japicmp/compat/CompatibilityChangesTest.java
Original file line number Diff line number Diff line change
@@ -758,10 +758,39 @@ public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
// assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
// assertThat(jApiClass.isBinaryCompatible(), is(false));
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiConstructor jApiConstructor = getJApiConstructor(jApiClass.getConstructors(), Collections.singletonList("int"));
assertThat(jApiConstructor.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.CONSTRUCTOR_LESS_ACCESSIBLE));
assertThat(jApiConstructor.isBinaryCompatible(), is(false));
}

@Test
public void testMethodAddedToInterface() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtInterfaceBuilder.create().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}

@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtInterfaceBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().abstractMethod().name("method").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(true));
assertThat(jApiClass.isSourceCompatible(), is(false));
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "method");
assertThat(jApiMethod.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.METHOD_ADDED_TO_INTERFACE));
assertThat(jApiMethod.isBinaryCompatible(), is(true));
assertThat(jApiMethod.isSourceCompatible(), is(false));
}
}

0 comments on commit 35f95ed

Please sign in to comment.