|  | 
|  | 1 | +package io.quarkus.flyway; | 
|  | 2 | + | 
|  | 3 | +import static org.objectweb.asm.Opcodes.ALOAD; | 
|  | 4 | +import static org.objectweb.asm.Opcodes.ASTORE; | 
|  | 5 | +import static org.objectweb.asm.Opcodes.DUP; | 
|  | 6 | +import static org.objectweb.asm.Opcodes.GETFIELD; | 
|  | 7 | +import static org.objectweb.asm.Opcodes.INVOKEINTERFACE; | 
|  | 8 | +import static org.objectweb.asm.Opcodes.INVOKESPECIAL; | 
|  | 9 | +import static org.objectweb.asm.Opcodes.NEW; | 
|  | 10 | +import static org.objectweb.asm.Opcodes.POP; | 
|  | 11 | +import static org.objectweb.asm.Opcodes.PUTFIELD; | 
|  | 12 | +import static org.objectweb.asm.Opcodes.RETURN; | 
|  | 13 | + | 
|  | 14 | +import java.util.function.BiFunction; | 
|  | 15 | + | 
|  | 16 | +import org.flywaydb.core.internal.scanner.Scanner; | 
|  | 17 | +import org.flywaydb.core.internal.scanner.classpath.ResourceAndClassScanner; | 
|  | 18 | +import org.objectweb.asm.ClassVisitor; | 
|  | 19 | +import org.objectweb.asm.MethodVisitor; | 
|  | 20 | + | 
|  | 21 | +import io.quarkus.flyway.runtime.QuarkusPathLocationScanner; | 
|  | 22 | +import io.quarkus.gizmo.Gizmo; | 
|  | 23 | + | 
|  | 24 | +class ScannerTransformer implements BiFunction<String, ClassVisitor, ClassVisitor> { | 
|  | 25 | + | 
|  | 26 | +    static final String FLYWAY_SCANNER_CLASS_NAME = Scanner.class.getName(); | 
|  | 27 | +    private static final String FLYWAY_SCANNER_INTERNAL_CLASS_NAME = FLYWAY_SCANNER_CLASS_NAME.replace('.', '/'); | 
|  | 28 | + | 
|  | 29 | +    private static final String FLYWAY_RESOURCE_AND_CLASS_SCANNER_CLASS_NAME = ResourceAndClassScanner.class.getName(); | 
|  | 30 | +    private static final String FLYWAY_RESOURCE_AND_CLASS_SCANNER_INTERNAL_CLASS_NAME = FLYWAY_RESOURCE_AND_CLASS_SCANNER_CLASS_NAME | 
|  | 31 | +            .replace('.', '/'); | 
|  | 32 | + | 
|  | 33 | +    private static final String QUARKUS_RESOURCE_AND_CLASS_SCANNER_CLASS_NAME = QuarkusPathLocationScanner.class.getName(); | 
|  | 34 | +    private static final String QUARKUS_RESOURCE_AND_CLASS_SCANNER_INTERNAL_CLASS_NAME = QUARKUS_RESOURCE_AND_CLASS_SCANNER_CLASS_NAME | 
|  | 35 | +            .replace('.', '/'); | 
|  | 36 | + | 
|  | 37 | +    private static final String CTOR_METHOD_NAME = "<init>"; | 
|  | 38 | + | 
|  | 39 | +    @Override | 
|  | 40 | +    public ClassVisitor apply(String s, ClassVisitor cv) { | 
|  | 41 | +        return new ScannerVisitor(cv); | 
|  | 42 | +    } | 
|  | 43 | + | 
|  | 44 | +    private static final class ScannerVisitor extends ClassVisitor { | 
|  | 45 | + | 
|  | 46 | +        public ScannerVisitor(ClassVisitor cv) { | 
|  | 47 | +            super(Gizmo.ASM_API_VERSION, cv); | 
|  | 48 | +        } | 
|  | 49 | + | 
|  | 50 | +        @Override | 
|  | 51 | +        public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { | 
|  | 52 | +            MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); | 
|  | 53 | +            if (name.equals(CTOR_METHOD_NAME)) { | 
|  | 54 | +                return new ConstructorTransformer(mv); | 
|  | 55 | +            } | 
|  | 56 | +            return mv; | 
|  | 57 | +        } | 
|  | 58 | + | 
|  | 59 | +        /** | 
|  | 60 | +         * Replaces the constructor of the {@link Scanner} with: | 
|  | 61 | +         * | 
|  | 62 | +         * <pre> | 
|  | 63 | +         * public ScannerSubstitutions(Class<?> implementedInterface, Collection<Location> locations, ClassLoader classLoader, | 
|  | 64 | +         *         Charset encoding, ResourceNameCache resourceNameCache, LocationScannerCache locationScannerCache) { | 
|  | 65 | +         *     ResourceAndClassScanner quarkusScanner = new QuarkusPathLocationScanner(locations); | 
|  | 66 | +         *     resources.addAll(quarkusScanner.scanForResources()); | 
|  | 67 | +         *     classes.addAll(quarkusScanner.scanForClasses()); | 
|  | 68 | +         * } | 
|  | 69 | +         * </pre> | 
|  | 70 | +         */ | 
|  | 71 | +        private static class ConstructorTransformer extends MethodVisitor { | 
|  | 72 | + | 
|  | 73 | +            public ConstructorTransformer(MethodVisitor mv) { | 
|  | 74 | +                super(Gizmo.ASM_API_VERSION, mv); | 
|  | 75 | +            } | 
|  | 76 | + | 
|  | 77 | +            @Override | 
|  | 78 | +            public void visitCode() { | 
|  | 79 | +                super.visitVarInsn(ALOAD, 0); | 
|  | 80 | +                super.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", CTOR_METHOD_NAME, "()V", false); | 
|  | 81 | +                super.visitVarInsn(ALOAD, 0); | 
|  | 82 | +                super.visitTypeInsn(NEW, "java/util/ArrayList"); | 
|  | 83 | +                super.visitInsn(DUP); | 
|  | 84 | +                super.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", CTOR_METHOD_NAME, "()V", false); | 
|  | 85 | +                super.visitFieldInsn(PUTFIELD, FLYWAY_SCANNER_INTERNAL_CLASS_NAME, "resources", "Ljava/util/List;"); | 
|  | 86 | +                super.visitVarInsn(ALOAD, 0); | 
|  | 87 | +                super.visitTypeInsn(NEW, "java/util/ArrayList"); | 
|  | 88 | +                super.visitInsn(DUP); | 
|  | 89 | +                super.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", CTOR_METHOD_NAME, "()V", false); | 
|  | 90 | +                super.visitFieldInsn(PUTFIELD, FLYWAY_SCANNER_INTERNAL_CLASS_NAME, "classes", "Ljava/util/List;"); | 
|  | 91 | +                super.visitTypeInsn(NEW, QUARKUS_RESOURCE_AND_CLASS_SCANNER_INTERNAL_CLASS_NAME); | 
|  | 92 | +                super.visitInsn(DUP); | 
|  | 93 | +                super.visitVarInsn(ALOAD, 2); | 
|  | 94 | +                super.visitMethodInsn(INVOKESPECIAL, QUARKUS_RESOURCE_AND_CLASS_SCANNER_INTERNAL_CLASS_NAME, | 
|  | 95 | +                        CTOR_METHOD_NAME, "(Ljava/util/Collection;)V", false); | 
|  | 96 | +                super.visitVarInsn(ASTORE, 7); | 
|  | 97 | +                super.visitVarInsn(ALOAD, 0); | 
|  | 98 | +                super.visitFieldInsn(GETFIELD, FLYWAY_SCANNER_INTERNAL_CLASS_NAME, "resources", "Ljava/util/List;"); | 
|  | 99 | +                super.visitVarInsn(ALOAD, 7); | 
|  | 100 | +                super.visitMethodInsn(INVOKEINTERFACE, FLYWAY_RESOURCE_AND_CLASS_SCANNER_INTERNAL_CLASS_NAME, | 
|  | 101 | +                        "scanForResources", "()Ljava/util/Collection;", true); | 
|  | 102 | +                super.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "addAll", "(Ljava/util/Collection;)Z", true); | 
|  | 103 | +                super.visitInsn(POP); | 
|  | 104 | +                super.visitVarInsn(ALOAD, 0); | 
|  | 105 | +                super.visitFieldInsn(GETFIELD, FLYWAY_SCANNER_INTERNAL_CLASS_NAME, "classes", "Ljava/util/List;"); | 
|  | 106 | +                super.visitVarInsn(ALOAD, 7); | 
|  | 107 | +                super.visitMethodInsn(INVOKEINTERFACE, FLYWAY_RESOURCE_AND_CLASS_SCANNER_INTERNAL_CLASS_NAME, | 
|  | 108 | +                        "scanForClasses", "()Ljava/util/Collection;", true); | 
|  | 109 | +                super.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "addAll", "(Ljava/util/Collection;)Z", true); | 
|  | 110 | +                super.visitInsn(POP); | 
|  | 111 | +                super.visitInsn(RETURN); | 
|  | 112 | +                super.visitMaxs(3, 8); | 
|  | 113 | +            } | 
|  | 114 | +        } | 
|  | 115 | +    } | 
|  | 116 | +} | 
0 commit comments