Example usage for org.objectweb.asm.commons SerialVersionUIDAdder SerialVersionUIDAdder

List of usage examples for org.objectweb.asm.commons SerialVersionUIDAdder SerialVersionUIDAdder

Introduction

In this page you can find the example usage for org.objectweb.asm.commons SerialVersionUIDAdder SerialVersionUIDAdder.

Prototype

public SerialVersionUIDAdder(final ClassVisitor classVisitor) 

Source Link

Document

Constructs a new SerialVersionUIDAdder .

Usage

From source file:com.android.build.gradle.internal.incremental.IncrementalVisitor.java

License:Apache License

@Nullable
public static File instrumentClass(int targetApiLevel, @NonNull File inputRootDirectory,
        @NonNull File inputFile, @NonNull File outputDirectory, @NonNull VisitorBuilder visitorBuilder,
        @NonNull ILogger logger) throws IOException {

    byte[] classBytes;
    String path = FileUtils.relativePath(inputFile, inputRootDirectory);

    // if the class is not eligible for IR, return the non instrumented version or null if
    // the override class is requested.
    if (!isClassEligibleForInstantRun(inputFile)) {
        if (visitorBuilder.getOutputType() == OutputType.INSTRUMENT) {
            File outputFile = new File(outputDirectory, path);
            Files.createParentDirs(outputFile);
            Files.copy(inputFile, outputFile);
            return outputFile;
        } else {//  w  ww .  j a v a2 s  .co  m
            return null;
        }
    }
    classBytes = Files.toByteArray(inputFile);
    ClassReader classReader = new ClassReader(classBytes);
    // override the getCommonSuperClass to use the thread context class loader instead of
    // the system classloader. This is useful as ASM needs to load classes from the project
    // which the system classloader does not have visibility upon.
    // TODO: investigate if there is not a simpler way than overriding.
    ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES) {
        @Override
        protected String getCommonSuperClass(final String type1, final String type2) {
            Class<?> c, d;
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            try {
                c = Class.forName(type1.replace('/', '.'), false, classLoader);
                d = Class.forName(type2.replace('/', '.'), false, classLoader);
            } catch (ClassNotFoundException e) {
                // This may happen if we're processing class files which reference APIs not
                // available on the target device. In this case return a dummy value, since this
                // is ignored during dx compilation.
                return "instant/run/NoCommonSuperClass";
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            if (c.isAssignableFrom(d)) {
                return type1;
            }
            if (d.isAssignableFrom(c)) {
                return type2;
            }
            if (c.isInterface() || d.isInterface()) {
                return "java/lang/Object";
            } else {
                do {
                    c = c.getSuperclass();
                } while (!c.isAssignableFrom(d));
                return c.getName().replace('.', '/');
            }
        }
    };

    ClassNode classNode = AsmUtils.readClass(classReader);

    // when dealing with interface, we just copy the inputFile over without any changes unless
    // this is a package private interface.
    AccessRight accessRight = AccessRight.fromNodeAccess(classNode.access);
    File outputFile = new File(outputDirectory, path);
    if ((classNode.access & Opcodes.ACC_INTERFACE) != 0) {
        if (visitorBuilder.getOutputType() == OutputType.INSTRUMENT) {
            // don't change the name of interfaces.
            Files.createParentDirs(outputFile);
            if (accessRight == AccessRight.PACKAGE_PRIVATE) {
                classNode.access = classNode.access | Opcodes.ACC_PUBLIC;
                classNode.accept(classWriter);
                Files.write(classWriter.toByteArray(), outputFile);
            } else {
                // just copy the input file over, no change.
                Files.write(classBytes, outputFile);
            }
            return outputFile;
        } else {
            return null;
        }
    }

    AsmUtils.DirectoryBasedClassReader directoryClassReader = new AsmUtils.DirectoryBasedClassReader(
            getBinaryFolder(inputFile, classNode));

    // if we are targeting a more recent version than the current device, disable instant run
    // for that class.
    List<ClassNode> parentsNodes = isClassTargetingNewerPlatform(targetApiLevel, TARGET_API_TYPE,
            directoryClassReader, classNode, logger) ? ImmutableList.of()
                    : AsmUtils.parseParents(logger, directoryClassReader, classNode, targetApiLevel);
    // if we could not determine the parent hierarchy, disable instant run.
    if (parentsNodes.isEmpty() || isPackageInstantRunDisabled(inputFile)) {
        if (visitorBuilder.getOutputType() == OutputType.INSTRUMENT) {
            Files.createParentDirs(outputFile);
            Files.write(classBytes, outputFile);
            return outputFile;
        } else {
            return null;
        }
    }

    outputFile = new File(outputDirectory, visitorBuilder.getMangledRelativeClassFilePath(path));
    Files.createParentDirs(outputFile);
    IncrementalVisitor visitor = visitorBuilder.build(classNode, parentsNodes, classWriter, logger);

    if (visitorBuilder.getOutputType() == OutputType.INSTRUMENT) {
        /*
         * Classes that do not have a serial version unique identifier, will be updated to
         * contain one. This is accomplished by using the {@link SerialVersionUIDAdder} class
         * visitor that is added when this visitor is created (see the constructor). This way,
         * the serialVersionUID is the same for instrumented and non-instrumented classes. All
         * classes will have a serialVersionUID, so if some of the classes that is extended
         * starts implementing {@link java.io.Serializable}, serialization and deserialization
         * will continue to work correctly.
         */
        classNode.accept(new SerialVersionUIDAdder(visitor));
    } else {
        classNode.accept(visitor);
    }

    Files.write(classWriter.toByteArray(), outputFile);
    return outputFile;
}