public static void main(String[] args) throws IOException {
    Path directory = Paths.get(args[0]);
    System.out.println("rewrite directory " + directory);
    List<Path> paths = Files.walk(directory)
        .filter(path -> path.getFileName().toString().endsWith(".class"))
        .collect(Collectors.toList());
    List<ClassReader> readers = paths.stream()
        .map(Rewriter::openClassReader)
        .collect(Collectors.toList());
    Set<String> annotatedTypes = readers.parallelStream()
        .filter(InterceptedClassVisitor::isIntercepted)
        .map(classReader -> classReader.getClassName().replace('.', '/'))
        .collect(Collectors.toSet());
    
    System.out.println("found annotated types " + annotatedTypes);
    
    for(int i = 0; i < readers.size(); i++) {
       int index = i;
       ClassReader classReader = readers.get(i);
       ClassWriter classWriter = new ClassWriter(classReader, 0);
       classReader.accept(new ClassVisitor(Opcodes.ASM5, classWriter) {
         boolean modified;
         
         @Override
         public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
           MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
           return new MethodVisitor(Opcodes.ASM5, mv) {
             private void rewriteAsInvokedynamic(int methodHandleTag, String owner, String name, String desc) {
               
               return;
             }
             
             @Override
             public void visitMethodInsn(int opcode, String owner, String name, String desc) {
               int methodHandleTag;
               if (annotatedTypes.contains(owner) && (methodHandleTag = asMethodHandleTag(opcode)) != 0) {
                 Handle handle = new Handle(methodHandleTag, owner, name, desc);
                 String indyDesc = '(' + ((owner.charAt(0) == '[')? owner: 'L' + owner +';') + desc.substring(1);
                 visitInvokeDynamicInsn(name, indyDesc, BSM, handle);
                 modified = true;
                 return;
               }
               super.visitMethodInsn(opcode, owner, name, desc);
             }
             
             @Override
            public void visitFieldInsn(int opcode, String owner, String name, String desc) {
               int methodHandleTag;
               if (annotatedTypes.contains(owner) && (methodHandleTag = asMethodHandleTag(opcode)) != 0) {
                 Handle handle = new Handle(methodHandleTag, owner, name, desc);
                 String indyDesc = '(' + ((owner.charAt(0) == '[')? owner: 'L' + owner +';') + ')' + desc;
                 visitInvokeDynamicInsn(name, indyDesc, BSM, handle);
                 modified = true;
                 return;
               }
               super.visitFieldInsn(opcode, owner, name, desc);
             }
           };
         }
         
         @Override
        public void visitEnd() {
           super.visitEnd();
           if (modified) {
             try {
               Path path = paths.get(index);
               Files.write(path, classWriter.toByteArray());
               System.out.println("rewrite " + path);
             } catch(IOException e) {
               throw new RuntimeException(e);
             }
           }
         }
       }, 0);
     }
  }