List of usage examples for org.objectweb.asm.commons SerialVersionUIDAdder SerialVersionUIDAdder
public SerialVersionUIDAdder(final ClassVisitor classVisitor)
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; }