Search in sources :

Example 26 with SemanticVersioningClassVisitor

use of org.apache.aries.versioning.utils.SemanticVersioningClassVisitor 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);
}
Also used : BinaryCompatibilityStatus(org.apache.aries.versioning.utils.BinaryCompatibilityStatus) ClassReader(org.objectweb.asm.ClassReader) SemanticVersioningClassVisitor(org.apache.aries.versioning.utils.SemanticVersioningClassVisitor) ClassWriter(org.objectweb.asm.ClassWriter) Test(org.junit.Test)

Example 27 with SemanticVersioningClassVisitor

use of org.apache.aries.versioning.utils.SemanticVersioningClassVisitor 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));
    }
}
Also used : IFile(org.apache.aries.util.filesystem.IFile) ClassDeclaration(org.apache.aries.versioning.utils.ClassDeclaration) BinaryCompatibilityStatus(org.apache.aries.versioning.utils.BinaryCompatibilityStatus) MethodDeclaration(org.apache.aries.versioning.utils.MethodDeclaration) SemanticVersioningClassVisitor(org.apache.aries.versioning.utils.SemanticVersioningClassVisitor) HashMap(java.util.HashMap) Map(java.util.Map) FieldDeclaration(org.apache.aries.versioning.utils.FieldDeclaration)

Example 28 with SemanticVersioningClassVisitor

use of org.apache.aries.versioning.utils.SemanticVersioningClassVisitor in project aries by apache.

the class BundleCompatibility method getVisitor.

private SemanticVersioningClassVisitor getVisitor(IFile file, URLClassLoader loader) {
    SerialVersionClassVisitor sv = new SerialVersionClassVisitor(null);
    SemanticVersioningClassVisitor oldcv = new SemanticVersioningClassVisitor(loader, sv);
    try {
        ClassReader cr = new ClassReader(file.open());
        cr.accept(oldcv, 0);
    } catch (IOException ioe) {
        _logger.debug("The file " + file + "cannot be opened.");
    }
    return oldcv;
}
Also used : SerialVersionClassVisitor(org.apache.aries.versioning.utils.SerialVersionClassVisitor) ClassReader(org.objectweb.asm.ClassReader) IOException(java.io.IOException) SemanticVersioningClassVisitor(org.apache.aries.versioning.utils.SemanticVersioningClassVisitor)

Example 29 with SemanticVersioningClassVisitor

use of org.apache.aries.versioning.utils.SemanticVersioningClassVisitor in project aries by apache.

the class BinaryCompatibilityTest method test_jdk_chap13_4_15_3.

/**
     * Changing a static method that is not final to final is not a binary compatibility change.
     */
@Test
public void test_jdk_chap13_4_15_3() {
    ClassWriter cw = new ClassWriter(0);
    cw.visit(V1_5, ACC_PUBLIC, "pkg/Test", null, "versioning/java/files/TestA", null);
    cw.visitMethod(ACC_PUBLIC + 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_PUBLIC + ACC_STATIC + ACC_FINAL, "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);
    assertTrue("Changing a static method from non-final to final will not break binary compatibility.", newCV.getClassDeclaration().getBinaryCompatibleStatus((oldCV.getClassDeclaration())).isCompatible());
}
Also used : ClassReader(org.objectweb.asm.ClassReader) SemanticVersioningClassVisitor(org.apache.aries.versioning.utils.SemanticVersioningClassVisitor) ClassWriter(org.objectweb.asm.ClassWriter) Test(org.junit.Test)

Example 30 with SemanticVersioningClassVisitor

use of org.apache.aries.versioning.utils.SemanticVersioningClassVisitor 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());
}
Also used : BinaryCompatibilityStatus(org.apache.aries.versioning.utils.BinaryCompatibilityStatus) ClassReader(org.objectweb.asm.ClassReader) SemanticVersioningClassVisitor(org.apache.aries.versioning.utils.SemanticVersioningClassVisitor) ClassWriter(org.objectweb.asm.ClassWriter) Test(org.junit.Test)

Aggregations

SemanticVersioningClassVisitor (org.apache.aries.versioning.utils.SemanticVersioningClassVisitor)55 ClassReader (org.objectweb.asm.ClassReader)53 Test (org.junit.Test)52 ClassWriter (org.objectweb.asm.ClassWriter)52 BinaryCompatibilityStatus (org.apache.aries.versioning.utils.BinaryCompatibilityStatus)33 IFile (org.apache.aries.util.filesystem.IFile)2 MethodDeclaration (org.apache.aries.versioning.utils.MethodDeclaration)2 IOException (java.io.IOException)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 ClassDeclaration (org.apache.aries.versioning.utils.ClassDeclaration)1 FieldDeclaration (org.apache.aries.versioning.utils.FieldDeclaration)1 SerialVersionClassVisitor (org.apache.aries.versioning.utils.SerialVersionClassVisitor)1