diff --git a/japicmp/src/main/java/japicmp/compat/CompatibilityChanges.java b/japicmp/src/main/java/japicmp/compat/CompatibilityChanges.java index bc2ea174b..21bf6d967 100755 --- a/japicmp/src/main/java/japicmp/compat/CompatibilityChanges.java +++ b/japicmp/src/main/java/japicmp/compat/CompatibilityChanges.java @@ -264,6 +264,7 @@ private void checkIfConstructorsHaveChangedIncompatible(JApiClass jApiClass, Map addCompatibilityChange(constructor, JApiCompatibilityChange.CONSTRUCTOR_LESS_ACCESSIBLE); } } + checkIfExceptionIsNowChecked(constructor); checkIfAnnotationDeprecatedAdded(constructor); } } @@ -488,13 +489,13 @@ private boolean isAbstract(JApiHasAbstractModifier jApiHasAbstractModifier) { return isAbstract; } - private void checkIfExceptionIsNowChecked(JApiMethod method) { - for (JApiException exception : method.getExceptions()) { - if (exception.getChangeStatus() == JApiChangeStatus.NEW && exception.isCheckedException() && method.getChangeStatus() != JApiChangeStatus.NEW) { - addCompatibilityChange(method, JApiCompatibilityChange.METHOD_NOW_THROWS_CHECKED_EXCEPTION); + private void checkIfExceptionIsNowChecked(JApiBehavior behavior) { + for (JApiException exception : behavior.getExceptions()) { + if (exception.getChangeStatus() == JApiChangeStatus.NEW && exception.isCheckedException() && behavior.getChangeStatus() != JApiChangeStatus.NEW) { + addCompatibilityChange(behavior, JApiCompatibilityChange.METHOD_NOW_THROWS_CHECKED_EXCEPTION); } - if (exception.getChangeStatus() == JApiChangeStatus.REMOVED && exception.isCheckedException() && method.getChangeStatus() != JApiChangeStatus.REMOVED) { - addCompatibilityChange(method, JApiCompatibilityChange.METHOD_NO_LONGER_THROWS_CHECKED_EXCEPTION); + if (exception.getChangeStatus() == JApiChangeStatus.REMOVED && exception.isCheckedException() && behavior.getChangeStatus() != JApiChangeStatus.REMOVED) { + addCompatibilityChange(behavior, JApiCompatibilityChange.METHOD_NO_LONGER_THROWS_CHECKED_EXCEPTION); } } } diff --git a/japicmp/src/test/java/japicmp/compat/CompatibilityChangesTest.java b/japicmp/src/test/java/japicmp/compat/CompatibilityChangesTest.java index 81ecdd0e7..b1ce25afd 100755 --- a/japicmp/src/test/java/japicmp/compat/CompatibilityChangesTest.java +++ b/japicmp/src/test/java/japicmp/compat/CompatibilityChangesTest.java @@ -18,6 +18,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsNot.not; +import static org.junit.Assert.assertEquals; public class CompatibilityChangesTest { @@ -983,6 +984,56 @@ public List createNewClasses(ClassPool classPool) throws Exception { assertThat(jApiClass.isSourceCompatible(), is(true)); } + @Test + public void testConstructorThrowsNewCheckedException() throws Exception { + JarArchiveComparatorOptions options = new JarArchiveComparatorOptions(); + List jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() { + @Override + public List createOldClasses(ClassPool classPool) throws Exception { + CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool); + CtConstructorBuilder.create().publicAccess().addToClass(ctClass); + return Collections.singletonList(ctClass); + } + + @Override + public List createNewClasses(ClassPool classPool) throws Exception { + CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool); + CtConstructorBuilder.create().publicAccess().exceptions(new CtClass[] {classPool.get("java.lang.Exception")}).addToClass(ctClass); + return Collections.singletonList(ctClass); + } + }); + JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test"); + JApiConstructor constructor = jApiClass.getConstructors().get(0); + assertThat(constructor.isBinaryCompatible(), is(true)); + assertThat(constructor.isSourceCompatible(), is(false)); + assertEquals(constructor.getCompatibilityChanges(), Collections.singletonList(JApiCompatibilityChange.METHOD_NOW_THROWS_CHECKED_EXCEPTION)); + } + + @Test + public void testConstructorNoLongerThrowsNewCheckedException() throws Exception { + JarArchiveComparatorOptions options = new JarArchiveComparatorOptions(); + List jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() { + @Override + public List createOldClasses(ClassPool classPool) throws Exception { + CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool); + CtConstructorBuilder.create().publicAccess().exceptions(new CtClass[] {classPool.get("java.lang.Exception")}).addToClass(ctClass); + return Collections.singletonList(ctClass); + } + + @Override + public List createNewClasses(ClassPool classPool) throws Exception { + CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool); + CtConstructorBuilder.create().publicAccess().addToClass(ctClass); + return Collections.singletonList(ctClass); + } + }); + JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test"); + JApiConstructor constructor = jApiClass.getConstructors().get(0); + assertThat(constructor.isBinaryCompatible(), is(true)); + assertThat(constructor.isSourceCompatible(), is(false)); + assertEquals(constructor.getCompatibilityChanges(), Collections.singletonList(JApiCompatibilityChange.METHOD_NO_LONGER_THROWS_CHECKED_EXCEPTION)); + } + @Test public void testMethodAddedToInterface() throws Exception { JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();