use of org.apache.aries.versioning.utils.BinaryCompatibilityStatus in project aries by apache.
the class BinaryCompatibilityTest method test_jdk_chap13_4_13_1.
/**
* Changing a method return type is a binary compatibility change.
*/
@Test
public void test_jdk_chap13_4_13_1() {
ClassWriter cw = new ClassWriter(0);
cw.visit(V1_5, ACC_PUBLIC, "pkg/Test", null, "versioning/java/files/TestA", null);
cw.visitMethod(ACC_PUBLIC, "getCooLen", "(Ljava/lang/String;)I", null, null).visitEnd();
cw.visitEnd();
byte[] oldBytes = cw.toByteArray();
cw = new ClassWriter(0);
cw.visit(V1_5, ACC_PUBLIC, "pkg/Test", null, "versioning/java/files/TestA", null);
cw.visitField(ACC_PUBLIC + ACC_TRANSIENT, "aa", "Ljava/lang/String;", null, new String("newBar")).visitEnd();
cw.visitMethod(ACC_PUBLIC, "getCooLen", "(Ljava/lang/String;)[I", null, null).visitEnd();
cw.visitEnd();
byte[] newBytes = cw.toByteArray();
SemanticVersioningClassVisitor oldCV = new SemanticVersioningClassVisitor(loader);
SemanticVersioningClassVisitor newCV = new SemanticVersioningClassVisitor(loader);
ClassReader newCR = new ClassReader(newBytes);
ClassReader oldCR = new ClassReader(oldBytes);
newCR.accept(newCV, 0);
oldCR.accept(oldCV, 0);
BinaryCompatibilityStatus bcs = newCV.getClassDeclaration().getBinaryCompatibleStatus((oldCV.getClassDeclaration()));
assertEquals("The method int getCooLen(java.lang.String) has been deleted or its return type or parameter list has changed.", bcs.get(0));
assertTrue("Changing a method return type will break binary compatibility.", bcs.size() == 1);
}
use of org.apache.aries.versioning.utils.BinaryCompatibilityStatus in project aries by apache.
the class BinaryCompatibilityTest method test_jdk_chap13_4_12_2.
/**
* Changing a method parameter type is a binary compatibility change.
*/
@Test
public void test_jdk_chap13_4_12_2() {
ClassWriter cw = new ClassWriter(0);
cw.visit(V1_5, ACC_PUBLIC, "pkg/Test", null, "versioning/java/files/TestA", null);
cw.visitMethod(ACC_PUBLIC, "getCooLen", "(Ljava/lang/String;)I", null, null).visitEnd();
cw.visitEnd();
byte[] oldBytes = cw.toByteArray();
cw = new ClassWriter(0);
cw.visit(V1_5, ACC_PUBLIC, "pkg/Test", null, "versioning/java/files/TestA", null);
cw.visitField(ACC_PUBLIC + ACC_TRANSIENT, "aa", "Ljava/lang/String;", null, new String("newBar")).visitEnd();
cw.visitMethod(ACC_PUBLIC, "getCooLen", "(Ljava/lang/Object;)I", null, null).visitEnd();
cw.visitEnd();
byte[] newBytes = cw.toByteArray();
SemanticVersioningClassVisitor oldCV = new SemanticVersioningClassVisitor(loader);
SemanticVersioningClassVisitor newCV = new SemanticVersioningClassVisitor(loader);
ClassReader newCR = new ClassReader(newBytes);
ClassReader oldCR = new ClassReader(oldBytes);
newCR.accept(newCV, 0);
oldCR.accept(oldCV, 0);
BinaryCompatibilityStatus bcs = newCV.getClassDeclaration().getBinaryCompatibleStatus((oldCV.getClassDeclaration()));
assertEquals("The method int getCooLen(java.lang.String) has been deleted or its return type or parameter list has changed.", bcs.get(0));
assertTrue("Changing a method paramether type will break binary compatibility.", bcs.size() == 1);
}
use of org.apache.aries.versioning.utils.BinaryCompatibilityStatus in project aries by apache.
the class BundleCompatibility method visitPackage.
/**
* Visit the whole package to scan each class to see whether we need to log minor or major changes.
*
* @param pkgName
* @param baseClazz
* @param curClazz
* @param majorChange
* @param minorChange
*/
private void visitPackage(String pkgName, Map<String, IFile> baseClazz, Map<String, IFile> curClazz, VersionChangeReason majorChange, VersionChangeReason minorChange) {
StringBuilder major_reason = new StringBuilder();
StringBuilder minor_reason = new StringBuilder();
boolean is_major_change = false;
boolean is_minor_change = false;
String fatal_class = null;
boolean foundNewAbstract = false;
for (Map.Entry<String, IFile> file : baseClazz.entrySet()) {
// scan the latest version of the class
IFile curFile = curClazz.get(file.getKey());
String changeClass = file.getValue().getName();
//Scan the base version
SemanticVersioningClassVisitor oldcv = getVisitor(file.getValue(), oldJarsLoader);
// skip the property files as they are compiled as class file as well
ClassDeclaration cd = oldcv.getClassDeclaration();
if ((cd != null) && (!SemanticVersioningUtils.isPropertyFile(cd))) {
if (curFile == null) {
// the class we are scanning has been deleted from the current version of the bundle
// This should be a major increase
major_reason.append(twoLineBreaks + "The class/interface " + getClassName(changeClass) + " has been deleted from the package.");
//majorChange.update(reason, changeClass);
is_major_change = true;
// only replace the fatal class if not set as the class won't be found in cmvc due to the fact it has been deleted.
if (fatal_class == null) {
fatal_class = changeClass;
}
} else {
// check for binary compatibility
// load the class from the current version of the bundle
// remove it from the curClazz collection as we would like to know whether there are more classes added
curClazz.remove(file.getKey());
SemanticVersioningClassVisitor newcv = getVisitor(curFile, newJarsLoader);
// check for binary compatibility
ClassDeclaration newcd = newcv.getClassDeclaration();
BinaryCompatibilityStatus bcs = newcd.getBinaryCompatibleStatus(oldcv.getClassDeclaration());
if (!bcs.isCompatible()) {
major_reason.append(twoLineBreaks + "In the " + getClassName(changeClass) + " class or its supers, the following changes have been made since the last release.");
// break binary compatibility
for (String reason : bcs) {
major_reason.append(oneLineBreak).append(reason);
}
is_major_change = true;
fatal_class = changeClass;
} else {
//check to see whether more methods are added
ClassDeclaration oldcd = oldcv.getClassDeclaration();
Collection<MethodDeclaration> extraMethods = newcd.getExtraMethods(oldcd);
boolean containsConcrete = false;
boolean containsAbstract = false;
boolean abstractClass = newcd.isAbstract();
StringBuilder subRemarks = new StringBuilder();
String concreteSubRemarks = null;
for (MethodDeclaration extraMethod : extraMethods) {
//only interested in the visible methods not the system generated ones
if (!extraMethod.getName().contains("$")) {
if (abstractClass) {
if (extraMethod.isAbstract()) {
foundNewAbstract = true;
containsAbstract = true;
subRemarks.append(oneLineBreak + SemanticVersioningUtils.getReadableMethodSignature(extraMethod.getName(), extraMethod.getDesc()));
} else {
//only list one abstract method, no need to list all
containsConcrete = true;
concreteSubRemarks = oneLineBreak + SemanticVersioningUtils.getReadableMethodSignature(extraMethod.getName(), extraMethod.getDesc());
}
} else {
containsConcrete = true;
concreteSubRemarks = oneLineBreak + SemanticVersioningUtils.getReadableMethodSignature(extraMethod.getName(), extraMethod.getDesc());
break;
}
}
}
if (containsConcrete || containsAbstract) {
is_minor_change = true;
if (!is_major_change) {
fatal_class = changeClass;
}
if (containsAbstract) {
minor_reason.append(twoLineBreaks + "In the " + getClassName(changeClass) + " class or its supers, the following abstract methods have been added since the last release of this bundle.");
minor_reason.append(subRemarks);
} else {
minor_reason.append(twoLineBreaks + "In the " + getClassName(changeClass) + " class or its supers, the following method has been added since the last release of this bundle.");
minor_reason.append(concreteSubRemarks);
}
}
if (!is_minor_change) {
for (FieldDeclaration field : newcd.getExtraFields(oldcd)) {
if (field.isPublic() || field.isProtected()) {
is_minor_change = true;
String extraFieldRemarks = oneLineBreak + " " + SemanticVersioningUtils.transform(field.getDesc()) + " " + field.getName();
if (!is_major_change) {
fatal_class = changeClass;
}
minor_reason.append(twoLineBreaks + "In the " + getClassName(changeClass) + " class or its supers, the following fields have been added since the last release of this bundle.");
minor_reason.append(extraFieldRemarks);
break;
}
}
}
}
}
}
}
if (is_major_change) {
majorChange.update(major_reason.toString(), fatal_class, false);
}
if (is_minor_change) {
minorChange.update(minor_reason.toString(), fatal_class, (foundNewAbstract ? true : false));
}
}
use of org.apache.aries.versioning.utils.BinaryCompatibilityStatus in project aries by apache.
the class BinaryCompatibilityTest method test_jdk_chap13_4_17_3.
/**
* If a method is private was declared static and is changed to not be declared static, this does not break compatibility.
*/
@Test
public void test_jdk_chap13_4_17_3() {
ClassWriter cw = new ClassWriter(0);
cw.visit(V1_5, ACC_PUBLIC, "pkg/Test", null, "versioning/java/files/TestA", null);
cw.visitMethod(ACC_PRIVATE + ACC_STATIC, "getCooLen", "(Ljava/lang/String;)I", null, null).visitEnd();
cw.visitEnd();
byte[] oldBytes = cw.toByteArray();
cw = new ClassWriter(0);
cw.visit(V1_5, ACC_PUBLIC, "pkg/Test", null, "versioning/java/files/TestA", null);
cw.visitField(ACC_PUBLIC + ACC_TRANSIENT, "aa", "Ljava/lang/String;", null, new String("newBar")).visitEnd();
cw.visitMethod(ACC_PRIVATE, "getCooLen", "(Ljava/lang/String;)I", null, null).visitEnd();
cw.visitEnd();
byte[] newBytes = cw.toByteArray();
SemanticVersioningClassVisitor oldCV = new SemanticVersioningClassVisitor(loader);
SemanticVersioningClassVisitor newCV = new SemanticVersioningClassVisitor(loader);
ClassReader newCR = new ClassReader(newBytes);
ClassReader oldCR = new ClassReader(oldBytes);
newCR.accept(newCV, 0);
oldCR.accept(oldCV, 0);
BinaryCompatibilityStatus bcs = newCV.getClassDeclaration().getBinaryCompatibleStatus((oldCV.getClassDeclaration()));
assertTrue("If a method is private was declared static and is changed to not be decalared static, this should not break compatibility.", bcs.isCompatible());
}
use of org.apache.aries.versioning.utils.BinaryCompatibilityStatus in project aries by apache.
the class BinaryCompatibilityTest method test_jdk_chap13_4_8_1.
/**
* If a field was not final is changed to be final, then it can break compatibility.
*/
@Test
public void test_jdk_chap13_4_8_1() {
ClassWriter cw = new ClassWriter(0);
cw.visit(V1_5, ACC_PUBLIC, "pkg/Test", null, "versioning/java/files/TestA", null);
cw.visitField(ACC_PUBLIC, "aa", "Ljava/lang/String;", null, new String("newBar")).visitEnd();
cw.visitEnd();
byte[] oldBytes = cw.toByteArray();
cw = new ClassWriter(0);
cw.visit(V1_5, ACC_PUBLIC, "pkg/Test", null, "versioning/java/files/TestA", null);
cw.visitField(ACC_PUBLIC + ACC_FINAL, "aa", "Ljava/lang/String;", null, new String("newBar")).visitEnd();
cw.visitEnd();
byte[] newBytes = cw.toByteArray();
SemanticVersioningClassVisitor oldCV = new SemanticVersioningClassVisitor(loader);
SemanticVersioningClassVisitor newCV = new SemanticVersioningClassVisitor(loader);
ClassReader newCR = new ClassReader(newBytes);
ClassReader oldCR = new ClassReader(oldBytes);
newCR.accept(newCV, 0);
oldCR.accept(oldCV, 0);
BinaryCompatibilityStatus bcs = newCV.getClassDeclaration().getBinaryCompatibleStatus((oldCV.getClassDeclaration()));
assertEquals("The public field aa was not final but has been changed to be final.", bcs.get(0));
assertTrue("Change that a public or protected field was final but is changed to be not final will break binary compatibility.", bcs.size() == 1);
}
Aggregations