class CustomClassTransform extends Transform {

    @Override
    public void transform(@NonNull TransformInvocation invocation)
            throws InterruptedException, IOException {
        final TransformOutputProvider outputProvider = invocation.getOutputProvider();
        assert outputProvider != null;

        // Output the resources, we only do this if this is not incremental,
        // as the secondary file is will trigger a full build if modified.
        if (!invocation.isIncremental()) {
            outputProvider.deleteAll();

            if (addDependencies) {
                // To avoid https://bugs.openjdk.java.net/browse/JDK-7183373
                // we extract the resources directly as a zip file.
                try (ZipInputStream zis = new ZipInputStream(new FileInputStream(path))) {
                    ZipEntry entry;
                    Pattern pattern = Pattern.compile("dependencies/(.*)\\.jar");
                    while ((entry = zis.getNextEntry()) != null
                            && ZipEntryUtils.isValidZipEntryName(entry)) {
                        Matcher matcher = pattern.matcher(entry.getName());
                        if (matcher.matches()) {
                            String name = matcher.group(1);
                            File outputJar =
                                    outputProvider.getContentLocation(
                                            name, getOutputTypes(), SCOPE_EXTERNAL, Format.JAR);
                            Files.createParentDirs(outputJar);
                            try (FileOutputStream fos = new FileOutputStream(outputJar)) {
                                ByteStreams.copy(zis, fos);
                            }
                        }
                        zis.closeEntry();
                    }
                }
            }
        }

        URL url = new File(path).toURI().toURL();
        try (URLClassLoader loader = new URLClassLoader(new URL[] {url})) {
            BiConsumer<InputStream, OutputStream> function = loadTransformFunction(loader);

            for (TransformInput ti : invocation.getInputs()) {
                for (JarInput jarInput : ti.getJarInputs()) {
                    File inputJar = jarInput.getFile();
                    File outputJar =
                            outputProvider.getContentLocation(
                                    jarInput.getName(),
                                    jarInput.getContentTypes(),
                                    jarInput.getScopes(),
                                    Format.JAR);

                    if (invocation.isIncremental()) {
                        switch (jarInput.getStatus()) {
                            case NOTCHANGED:
                                break;
                            case ADDED:
                            case CHANGED:
                                transformJar(function, inputJar, outputJar);
                                break;
                            case REMOVED:
                                FileUtils.delete(outputJar);
                                break;
                        }
                    } else {
                        transformJar(function, inputJar, outputJar);
                    }
                }
                for (DirectoryInput di : ti.getDirectoryInputs()) {
                    File inputDir = di.getFile();
                    File outputDir =
                            outputProvider.getContentLocation(
                                    di.getName(),
                                    di.getContentTypes(),
                                    di.getScopes(),
                                    Format.DIRECTORY);
                    if (invocation.isIncremental()) {
                        for (Map.Entry<File, Status> entry : di.getChangedFiles().entrySet()) {
                            File inputFile = entry.getKey();
                            switch (entry.getValue()) {
                                case NOTCHANGED:
                                    break;
                                case ADDED:
                                case CHANGED:
                                    if (!inputFile.isDirectory()
                                            && inputFile.getName()
                                            .endsWith(SdkConstants.DOT_CLASS)) {
                                        File out = toOutputFile(outputDir, inputDir, inputFile);
                                        transformFile(function, inputFile, out);
                                    }
                                    break;
                                case REMOVED:
                                    File outputFile = toOutputFile(outputDir, inputDir, inputFile);
                                    FileUtils.deleteIfExists(outputFile);
                                    break;
                            }
                        }
                    } else {
                        for (File in : FileUtils.getAllFiles(inputDir)) {
                            if (in.getName().endsWith(SdkConstants.DOT_CLASS)) {
                                File out = toOutputFile(outputDir, inputDir, in);
                                transformFile(function, in, out);
                            }
                        }
                    }
                }
            }
        }
    }

    public  CustomClassTransform(@NonNull String path, boolean addDependencies);

}