class DexArchiveBuilderTransform extends Transform {

    @Override
    public void transform(@NonNull TransformInvocation transformInvocation)
            throws TransformException, IOException, InterruptedException {
        TransformOutputProvider outputProvider = transformInvocation.getOutputProvider();
        Preconditions.checkNotNull(outputProvider, "Missing output provider.");
        if (dexOptions.getAdditionalParameters().contains("--no-optimize")) {
            logger.warning(DefaultDexOptions.OPTIMIZE_WARNING);
        }

        logger.verbose("Task is incremental : %b ", transformInvocation.isIncremental());

        if (!transformInvocation.isIncremental()) {
            outputProvider.deleteAll();
        }

        Set<File> additionalPaths;
        DesugarIncrementalTransformHelper desugarIncrementalTransformHelper;
        if (java8LangSupportType != VariantScope.Java8LangSupport.D8) {
            additionalPaths = ImmutableSet.of();
            desugarIncrementalTransformHelper = null;
        } else {
            desugarIncrementalTransformHelper =
                    new DesugarIncrementalTransformHelper(
                            projectVariant, transformInvocation, executor);
            additionalPaths =
                    desugarIncrementalTransformHelper
                            .getAdditionalPaths()
                            .stream()
                            .map(Path::toFile)
                            .collect(Collectors.toSet());
        }

        List<DexArchiveBuilderCacheHandler.CacheableItem> cacheableItems = new ArrayList<>();
        boolean isIncremental = transformInvocation.isIncremental();
        List<Path> classpath =
                getClasspath(transformInvocation, java8LangSupportType)
                        .stream()
                        .map(Paths::get)
                        .collect(Collectors.toList());
        List<Path> bootclasspath =
                getBootClasspath(androidJarClasspath, java8LangSupportType)
                        .stream()
                        .map(Paths::get)
                        .collect(Collectors.toList());

        ClasspathServiceKey bootclasspathServiceKey = null;
        ClasspathServiceKey classpathServiceKey = null;
        try (ClassFileProviderFactory bootClasspathProvider =
                        new ClassFileProviderFactory(bootclasspath);
                ClassFileProviderFactory libraryClasspathProvider =
                        new ClassFileProviderFactory(classpath)) {
            bootclasspathServiceKey = new ClasspathServiceKey(bootClasspathProvider.getId());
            classpathServiceKey = new ClasspathServiceKey(libraryClasspathProvider.getId());
            INSTANCE.registerService(
                    bootclasspathServiceKey, () -> new ClasspathService(bootClasspathProvider));
            INSTANCE.registerService(
                    classpathServiceKey, () -> new ClasspathService(libraryClasspathProvider));

            for (TransformInput input : transformInvocation.getInputs()) {

                for (DirectoryInput dirInput : input.getDirectoryInputs()) {
                    logger.verbose("Dir input %s", dirInput.getFile().toString());
                    convertToDexArchive(
                            transformInvocation.getContext(),
                            dirInput,
                            outputProvider,
                            isIncremental,
                            bootclasspathServiceKey,
                            classpathServiceKey,
                            additionalPaths);
                }

                for (JarInput jarInput : input.getJarInputs()) {
                    logger.verbose("Jar input %s", jarInput.getFile().toString());

                    D8DesugaringCacheInfo cacheInfo =
                            getD8DesugaringCacheInfo(
                                    desugarIncrementalTransformHelper,
                                    bootclasspath,
                                    classpath,
                                    jarInput);

                    List<File> dexArchives =
                            processJarInput(
                                    transformInvocation.getContext(),
                                    isIncremental,
                                    jarInput,
                                    outputProvider,
                                    bootclasspathServiceKey,
                                    classpathServiceKey,
                                    additionalPaths,
                                    cacheInfo);
                    if (cacheInfo != D8DesugaringCacheInfo.DONT_CACHE && !dexArchives.isEmpty()) {
                        cacheableItems.add(
                                new DexArchiveBuilderCacheHandler.CacheableItem(
                                        jarInput,
                                        dexArchives,
                                        cacheInfo.orderedD8DesugaringDependencies));
                    }
                }
            }

            // all work items have been submitted, now wait for completion.
            if (useGradleWorkers) {
                transformInvocation.getContext().getWorkerExecutor().await();
            } else {
                executor.waitForTasksWithQuickFail(true);
            }

            // if we are in incremental mode, delete all removed files.
            if (transformInvocation.isIncremental()) {
                for (TransformInput transformInput : transformInvocation.getInputs()) {
                    removeDeletedEntries(outputProvider, transformInput);
                }
            }

            // and finally populate the caches.
            if (!cacheableItems.isEmpty()) {
                cacheHandler.populateCache(cacheableItems);
            }

            logger.verbose("Done with all dex archive conversions");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new TransformException(e);
        } catch (Exception e) {
            PluginCrashReporter.maybeReportException(e);
            logger.error(null, Throwables.getStackTraceAsString(e));
            throw new TransformException(e);
        } finally {
            if (classpathServiceKey != null) {
                INSTANCE.removeService(classpathServiceKey);
            }
            if (bootclasspathServiceKey != null) {
                INSTANCE.removeService(bootclasspathServiceKey);
            }
        }
    }

      DexArchiveBuilderTransform(
            @NonNull Supplier<List<File>> androidJarClasspath,
            @NonNull DexOptions dexOptions,
            @NonNull MessageReceiver messageReceiver,
            @Nullable FileCache userLevelCache,
            int minSdkVersion,
            @NonNull DexerTool dexer,
            boolean useGradleWorkers,
            @Nullable Integer inBufferSize,
            @Nullable Integer outBufferSize,
            boolean isDebuggable,
            @NonNull VariantScope.Java8LangSupport java8LangSupportType,
            @NonNull String projectVariant,
            @Nullable Integer numberOfBuckets,
            boolean includeFeaturesInScopes,
            boolean isInstantRun,
            boolean enableDexingArtifactTransform);

}