class DexMergerTransform extends Transform {

    @Override
    public void transform(@NonNull TransformInvocation transformInvocation)
            throws TransformException, IOException, InterruptedException {
        TransformOutputProvider outputProvider = transformInvocation.getOutputProvider();
        Preconditions.checkNotNull(
                outputProvider, "Missing output object for transform " + getName());

        ProcessOutputHandler outputHandler =
                new ParsingProcessOutputHandler(
                        new ToolOutputParser(new DexParser(), Message.Kind.ERROR, logger),
                        new ToolOutputParser(new DexParser(), logger),
                        messageReceiver);

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

        ProcessOutput output = null;
        List<ForkJoinTask<Void>> mergeTasks;
        try (Closeable ignored = output = outputHandler.createOutput()) {
            if (dexingType == DexingType.NATIVE_MULTIDEX && isDebuggable) {
                mergeTasks =
                        handleNativeMultiDexDebug(
                                transformInvocation.getInputs(),
                                output,
                                outputProvider,
                                transformInvocation.isIncremental());
            } else {
                mergeTasks = mergeDex(transformInvocation.getInputs(), output, outputProvider);
            }

            // now wait for all merge tasks completion
            mergeTasks.forEach(ForkJoinTask::join);
        } catch (Exception e) {
            PluginCrashReporter.maybeReportException(e);
            // Print the error always, even without --stacktrace
            logger.error(null, Throwables.getStackTraceAsString(e));
            throw new TransformException(e);
        } finally {
            if (output != null) {
                try {
                    outputHandler.handleOutput(output);
                } catch (ProcessException e) {
                    // ignore this one
                }
            }
            forkJoinPool.shutdown();
            forkJoinPool.awaitTermination(100, TimeUnit.SECONDS);
        }
    }

    public  DexMergerTransform(
            @NonNull DexingType dexingType,
            @Nullable BuildableArtifact mainDexListFile,
            @NonNull BuildableArtifact duplicateClassesCheck,
            @NonNull MessageReceiver messageReceiver,
            @NonNull DexMergerTool dexMerger,
            int minSdkVersion,
            boolean isDebuggable,
            boolean includeFeaturesInScopes,
            boolean isInInstantRunMode);

}