You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by cs...@apache.org on 2022/04/08 19:19:57 UTC

[maven-resolver] branch artifact-transformer created (now c3fe83fe)

This is an automated email from the ASF dual-hosted git repository.

cstamas pushed a change to branch artifact-transformer
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git


      at c3fe83fe Proposed replacement for OOM-prone FileTransformer API.

This branch includes the following new commits:

     new c3fe83fe Proposed replacement for OOM-prone FileTransformer API.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[maven-resolver] 01/01: Proposed replacement for OOM-prone FileTransformer API.

Posted by cs...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

cstamas pushed a commit to branch artifact-transformer
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git

commit c3fe83fe44761b18f24717ff7d523d7f9e8207d5
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Fri Apr 8 21:18:02 2022 +0200

    Proposed replacement for OOM-prone FileTransformer API.
    
    The new ArtifactTransformer is as it's name says: for given
    artifact it can return zero, one or more (transformed or same or
    whatever) artifacts. All the work is delegated away from
    resolver, as transformer implementor does all the work, no
    magic happens in resolver.
---
 .../AbstractForwardingRepositorySystemSession.java |  6 +-
 .../aether/DefaultRepositorySystemSession.java     | 29 ++++-----
 .../eclipse/aether/RepositorySystemSession.java    |  4 +-
 ...leTransformer.java => ArtifactTransformer.java} | 32 +++-------
 ...anager.java => ArtifactTransformerManager.java} | 26 +++-----
 .../aether/transform/TransformException.java       | 72 ----------------------
 .../connector/basic/BasicRepositoryConnector.java  | 46 ++------------
 .../aether/internal/impl/DefaultDeployer.java      | 30 ++++-----
 .../aether/internal/impl/DefaultInstaller.java     | 51 +++++----------
 .../aether/internal/impl/DefaultDeployerTest.java  | 26 +++-----
 .../aether/internal/impl/DefaultInstallerTest.java | 28 ++++-----
 ...er.java => StubArtifactTransformerManager.java} | 20 +++---
 .../aether/spi/connector/ArtifactUpload.java       | 42 +------------
 13 files changed, 103 insertions(+), 309 deletions(-)

diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/AbstractForwardingRepositorySystemSession.java b/maven-resolver-api/src/main/java/org/eclipse/aether/AbstractForwardingRepositorySystemSession.java
index 008a2df5..b2b0f724 100644
--- a/maven-resolver-api/src/main/java/org/eclipse/aether/AbstractForwardingRepositorySystemSession.java
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/AbstractForwardingRepositorySystemSession.java
@@ -36,7 +36,7 @@ import org.eclipse.aether.repository.WorkspaceReader;
 import org.eclipse.aether.resolution.ArtifactDescriptorPolicy;
 import org.eclipse.aether.resolution.ResolutionErrorPolicy;
 import org.eclipse.aether.transfer.TransferListener;
-import org.eclipse.aether.transform.FileTransformerManager;
+import org.eclipse.aether.transform.ArtifactTransformerManager;
 
 /**
  * A special repository system session to enable decorating or proxying another session. To do so, clients have to
@@ -213,9 +213,9 @@ public abstract class AbstractForwardingRepositorySystemSession
     }
     
     @Override
-    public FileTransformerManager getFileTransformerManager()
+    public ArtifactTransformerManager getArtifactTransformerManager()
     {
-        return getSession().getFileTransformerManager();
+        return getSession().getArtifactTransformerManager();
     }
 
 }
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultRepositorySystemSession.java b/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultRepositorySystemSession.java
index 90b32f48..1cb0085e 100644
--- a/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultRepositorySystemSession.java
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultRepositorySystemSession.java
@@ -47,8 +47,8 @@ import org.eclipse.aether.repository.WorkspaceReader;
 import org.eclipse.aether.resolution.ArtifactDescriptorPolicy;
 import org.eclipse.aether.resolution.ResolutionErrorPolicy;
 import org.eclipse.aether.transfer.TransferListener;
-import org.eclipse.aether.transform.FileTransformer;
-import org.eclipse.aether.transform.FileTransformerManager;
+import org.eclipse.aether.transform.ArtifactTransformer;
+import org.eclipse.aether.transform.ArtifactTransformerManager;
 
 /**
  * A simple repository system session.
@@ -78,7 +78,7 @@ public final class DefaultRepositorySystemSession
 
     private LocalRepositoryManager localRepositoryManager;
 
-    private FileTransformerManager fileTransformerManager;
+    private ArtifactTransformerManager artifactTransformerManager;
 
     private WorkspaceReader workspaceReader;
 
@@ -137,7 +137,7 @@ public final class DefaultRepositorySystemSession
         proxySelector = NullProxySelector.INSTANCE;
         authenticationSelector = NullAuthenticationSelector.INSTANCE;
         artifactTypeRegistry = NullArtifactTypeRegistry.INSTANCE;
-        fileTransformerManager = NullFileTransformerManager.INSTANCE;
+        artifactTransformerManager = NullArtifactTransformerManager.INSTANCE;
         data = new DefaultSessionData();
     }
 
@@ -175,7 +175,7 @@ public final class DefaultRepositorySystemSession
         setDependencySelector( session.getDependencySelector() );
         setVersionFilter( session.getVersionFilter() );
         setDependencyGraphTransformer( session.getDependencyGraphTransformer() );
-        setFileTransformerManager( session.getFileTransformerManager() );
+        setArtifactTransformerManager( session.getArtifactTransformerManager() );
         setData( session.getData() );
         setCache( session.getCache() );
     }
@@ -329,18 +329,19 @@ public final class DefaultRepositorySystemSession
     }
 
     @Override
-    public FileTransformerManager getFileTransformerManager()
+    public ArtifactTransformerManager getArtifactTransformerManager()
     {
-        return fileTransformerManager;
+        return artifactTransformerManager;
     }
 
-    public DefaultRepositorySystemSession setFileTransformerManager( FileTransformerManager fileTransformerManager )
+    public DefaultRepositorySystemSession setArtifactTransformerManager(
+            ArtifactTransformerManager artifactTransformerManager )
     {
         failIfReadOnly();
-        this.fileTransformerManager = fileTransformerManager;
-        if ( this.fileTransformerManager == null )
+        this.artifactTransformerManager = artifactTransformerManager;
+        if ( this.artifactTransformerManager == null )
         {
-            this.fileTransformerManager = NullFileTransformerManager.INSTANCE;
+            this.artifactTransformerManager = NullArtifactTransformerManager.INSTANCE;
         }
         return this;
     }
@@ -862,12 +863,12 @@ public final class DefaultRepositorySystemSession
 
     }
 
-    static final class NullFileTransformerManager implements FileTransformerManager
+    static final class NullArtifactTransformerManager implements ArtifactTransformerManager
     {
-        public static final FileTransformerManager INSTANCE = new NullFileTransformerManager();
+        public static final ArtifactTransformerManager INSTANCE = new NullArtifactTransformerManager();
 
         @Override
-        public Collection<FileTransformer> getTransformersForArtifact( Artifact artifact )
+        public Collection<ArtifactTransformer> getTransformersForArtifact( Artifact artifact )
         {
             return Collections.emptyList();
         }
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java
index 5a3f14c2..02431fad 100644
--- a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java
@@ -37,7 +37,7 @@ import org.eclipse.aether.repository.WorkspaceReader;
 import org.eclipse.aether.resolution.ArtifactDescriptorPolicy;
 import org.eclipse.aether.resolution.ResolutionErrorPolicy;
 import org.eclipse.aether.transfer.TransferListener;
-import org.eclipse.aether.transform.FileTransformerManager;
+import org.eclipse.aether.transform.ArtifactTransformerManager;
 
 /**
  * Defines settings and components that control the repository system. Once initialized, the session object itself is
@@ -266,6 +266,6 @@ public interface RepositorySystemSession
      * 
      * @return the manager, never {@code null}
      */
-    FileTransformerManager getFileTransformerManager();
+    ArtifactTransformerManager getArtifactTransformerManager();
 
 }
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/transform/FileTransformer.java b/maven-resolver-api/src/main/java/org/eclipse/aether/transform/ArtifactTransformer.java
similarity index 53%
rename from maven-resolver-api/src/main/java/org/eclipse/aether/transform/FileTransformer.java
rename to maven-resolver-api/src/main/java/org/eclipse/aether/transform/ArtifactTransformer.java
index 45c0b5b1..92b81eb7 100644
--- a/maven-resolver-api/src/main/java/org/eclipse/aether/transform/FileTransformer.java
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/transform/ArtifactTransformer.java
@@ -19,39 +19,23 @@ package org.eclipse.aether.transform;
  * under the License.
  */
 
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
+import java.util.Collection;
 
 import org.eclipse.aether.artifact.Artifact;
 
 /**
- * Can transform a file while installing/deploying
+ * Artifact transformer that is invoked during installing/deploying
  * 
- * @author Robert Scholte
- * @since 1.3.0
- * @deprecated Without any direct replacement for now. This API is OOM-prone, and also lacks a lot of context about
- * transforming.
+ * @since 1.8.0
  */
-@Deprecated
-public interface FileTransformer
+public interface ArtifactTransformer
 {
     /**
-     * Transform the target location  
+     * Transform the artifact. This method may return empty collection (prevents install/deploy), return one
+     * artifact (same one or replaced one), or may even return more artifacts (injecting new ones).
      * 
      * @param artifact the original artifact
-     * @return the transformed artifact
+     * @return the list of transformed artifacts, never {@code null}
      */
-    Artifact transformArtifact( Artifact artifact );
-    
-    /**
-     * Transform the data
-     * 
-     * @param file the file with the original data
-     * @return the transformed data
-     * @throws IOException If an I/O error occurred
-     * @throws TransformException If the file could not be transformed
-     */
-    InputStream transformData( File file )
-        throws IOException, TransformException;
+    Collection<Artifact> transformArtifact( Artifact artifact );
 }
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/transform/FileTransformerManager.java b/maven-resolver-api/src/main/java/org/eclipse/aether/transform/ArtifactTransformerManager.java
similarity index 51%
rename from maven-resolver-api/src/main/java/org/eclipse/aether/transform/FileTransformerManager.java
rename to maven-resolver-api/src/main/java/org/eclipse/aether/transform/ArtifactTransformerManager.java
index 1a472e59..6a4b865a 100644
--- a/maven-resolver-api/src/main/java/org/eclipse/aether/transform/FileTransformerManager.java
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/transform/ArtifactTransformerManager.java
@@ -24,29 +24,17 @@ import java.util.Collection;
 import org.eclipse.aether.artifact.Artifact;
 
 /**
- * Manager the FileTransformers 
+ * Manager the {@link ArtifactTransformer}s.
  * 
- * @author Robert Scholte
- * @since 1.3.0
- * @deprecated Without any direct replacement for now. This API is OOM-prone, and also lacks a lot of context about
- * transforming.
+ * @since 1.8.0
  */
-@Deprecated
-public interface FileTransformerManager
+public interface ArtifactTransformerManager
 {
     /**
-     * <p>
-     * All transformers for this specific artifact. Be aware that if you want to create additional files, but also want
-     * to the original to be deployed, you must add an explicit transformer for that file too (one that doesn't
-     * transform the artifact and data).
-     * </p>
-     * 
-     * <p><strong>IMPORTANT</strong> When using a fileTransformer, the content of the file is stored in memory to ensure
-     * that file content and checksums stay in sync!
-     * </p>
-     * 
+     * All transformers for this specific artifact.
+     *
      * @param artifact the artifact
-     * @return a collection of FileTransformers to apply on the artifact, never {@code null}
+     * @return a collection of ArtifactTransformer to apply on the artifact, never {@code null}
      */
-    Collection<FileTransformer> getTransformersForArtifact( Artifact artifact );
+    Collection<ArtifactTransformer> getTransformersForArtifact( Artifact artifact );
 }
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/transform/TransformException.java b/maven-resolver-api/src/main/java/org/eclipse/aether/transform/TransformException.java
deleted file mode 100644
index 748b39d2..00000000
--- a/maven-resolver-api/src/main/java/org/eclipse/aether/transform/TransformException.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.eclipse.aether.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * Thrown when transformation failed.
- *
- * @deprecated Without any direct replacement for now. This API is OOM-prone, and also lacks a lot of context about
- * transforming.
- */
-@Deprecated
-public class TransformException
-    extends Exception
-{
-
-    /**
-     * Creates a new exception with default detail message.
-     */
-    public TransformException()
-    {
-        super( "Transformation failed" );
-    }
-
-    /**
-     * Creates a new exception with the specified detail message.
-     *
-     * @param message The detail message, may be {@code null}.
-     */
-    public TransformException( String message )
-    {
-        super( message );
-    }
-
-    /**
-     * Creates a new exception with the specified cause.
-     *
-     * @param cause The exception that caused this one, may be {@code null}.
-     */
-    public TransformException( Throwable cause )
-    {
-        super( cause );
-    }
-
-    /**
-     * Creates a new exception with the specified detail message and cause.
-     *
-     * @param message The detail message, may be {@code null}.
-     * @param cause   The exception that caused this one, may be {@code null}.
-     */
-    public TransformException( String message, Throwable cause )
-    {
-        super( message, cause );
-    }
-
-}
diff --git a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java
index e292de33..6c531f65 100644
--- a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java
+++ b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java
@@ -21,10 +21,8 @@ package org.eclipse.aether.connector.basic;
 
 import static java.util.Objects.requireNonNull;
 
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -65,7 +63,6 @@ import org.eclipse.aether.transfer.NoRepositoryLayoutException;
 import org.eclipse.aether.transfer.NoTransporterException;
 import org.eclipse.aether.transfer.TransferEvent;
 import org.eclipse.aether.transfer.TransferResource;
-import org.eclipse.aether.transform.FileTransformer;
 import org.eclipse.aether.util.ConfigUtils;
 import org.eclipse.aether.util.concurrency.RunnableErrorForwarder;
 import org.eclipse.aether.util.concurrency.WorkerThreadFactory;
@@ -313,8 +310,7 @@ final class BasicRepositoryConnector
             List<RepositoryLayout.ChecksumLocation> checksumLocations =
                     layout.getChecksumLocations( transfer.getArtifact(), true, location );
 
-            Runnable task = new PutTaskRunner( location, transfer.getFile(), transfer.getFileTransformer(),
-                    checksumLocations, listener );
+            Runnable task = new PutTaskRunner( location, transfer.getFile(), checksumLocations, listener );
             task.run();
         }
 
@@ -539,33 +535,20 @@ final class BasicRepositoryConnector
 
         private final File file;
 
-        private final FileTransformer fileTransformer;
-
         private final Collection<RepositoryLayout.ChecksumLocation> checksumLocations;
 
-        PutTaskRunner( URI path, File file, List<RepositoryLayout.ChecksumLocation> checksumLocations,
-                       TransferTransportListener<?> listener )
-        {
-            this( path, file, null, checksumLocations, listener );
-        }
-
         /**
-         * <strong>IMPORTANT</strong> When using a fileTransformer, the content of the file is stored in memory to
-         * ensure that file content and checksums stay in sync!
-         *
          * @param path
          * @param file
-         * @param fileTransformer
          * @param checksumLocations
          * @param listener
          */
-        PutTaskRunner( URI path, File file, FileTransformer fileTransformer,
+        PutTaskRunner( URI path, File file,
                        List<RepositoryLayout.ChecksumLocation> checksumLocations,
                        TransferTransportListener<?> listener )
         {
             super( path, listener );
             this.file = requireNonNull( file, "source file cannot be null" );
-            this.fileTransformer = fileTransformer;
             this.checksumLocations = safe( checksumLocations );
         }
 
@@ -574,29 +557,8 @@ final class BasicRepositoryConnector
         protected void runTask()
                 throws Exception
         {
-            if ( fileTransformer != null )
-            {
-                // transform data once to byte array, ensure constant data for checksum
-                ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                byte[] buffer = new byte[1024];
-
-                try ( InputStream transformData = fileTransformer.transformData( file ) )
-                {
-                    for ( int read; ( read = transformData.read( buffer, 0, buffer.length ) ) != -1; )
-                    {
-                        baos.write( buffer, 0, read );
-                    }
-                }
-
-                byte[] bytes = baos.toByteArray();
-                transporter.put( new PutTask( path ).setDataBytes( bytes ).setListener( listener ) );
-                uploadChecksums( file, bytes );
-            }
-            else
-            {
-                transporter.put( new PutTask( path ).setDataFile( file ).setListener( listener ) );
-                uploadChecksums( file, null );
-            }
+            transporter.put( new PutTask( path ).setDataFile( file ).setListener( listener ) );
+            uploadChecksums( file, null );
         }
 
         /**
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDeployer.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDeployer.java
index f582f50d..25e08887 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDeployer.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDeployer.java
@@ -74,8 +74,8 @@ import org.eclipse.aether.transfer.NoRepositoryConnectorException;
 import org.eclipse.aether.transfer.RepositoryOfflineException;
 import org.eclipse.aether.transfer.TransferCancelledException;
 import org.eclipse.aether.transfer.TransferEvent;
-import org.eclipse.aether.transform.FileTransformer;
-import org.eclipse.aether.transform.FileTransformerManager;
+import org.eclipse.aether.transform.ArtifactTransformer;
+import org.eclipse.aether.transform.ArtifactTransformerManager;
 
 /**
  */
@@ -243,7 +243,7 @@ public class DefaultDeployer
         {
             List<? extends MetadataGenerator> generators = getMetadataGenerators( session, request );
 
-            FileTransformerManager fileTransformerManager = session.getFileTransformerManager();
+            ArtifactTransformerManager artifactTransformerManager = session.getArtifactTransformerManager();
 
             List<ArtifactUpload> artifactUploads = new ArrayList<>();
             List<MetadataUpload> metadataUploads = new ArrayList<>();
@@ -274,19 +274,21 @@ public class DefaultDeployer
 
                 iterator.set( artifact );
 
-                Collection<FileTransformer> fileTransformers =
-                        fileTransformerManager.getTransformersForArtifact( artifact );
-                if ( !fileTransformers.isEmpty() )
+                Collection<ArtifactTransformer> artifactTransformers =
+                        artifactTransformerManager.getTransformersForArtifact( artifact );
+                if ( !artifactTransformers.isEmpty() )
                 {
-                    for ( FileTransformer fileTransformer : fileTransformers )
+                    for ( ArtifactTransformer artifactTransformer : artifactTransformers )
                     {
-                        Artifact targetArtifact = fileTransformer.transformArtifact( artifact );
-
-                        ArtifactUpload upload = new ArtifactUpload( targetArtifact, artifact.getFile(),
-                                fileTransformer );
-                        upload.setTrace( trace );
-                        upload.setListener( new ArtifactUploadListener( catapult, upload ) );
-                        artifactUploads.add( upload );
+                        Collection<Artifact> transformedArtifacts = artifactTransformer.transformArtifact( artifact );
+                        for ( Artifact transformedArtifact : transformedArtifacts )
+                        {
+                            ArtifactUpload upload = new ArtifactUpload(
+                                    transformedArtifact, transformedArtifact.getFile() );
+                            upload.setTrace( trace );
+                            upload.setListener( new ArtifactUploadListener( catapult, upload ) );
+                            artifactUploads.add( upload );
+                        }
                     }
                 }
                 else
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultInstaller.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultInstaller.java
index 6b3f7a7d..604fb7c4 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultInstaller.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultInstaller.java
@@ -22,7 +22,6 @@ package org.eclipse.aether.internal.impl;
 import static java.util.Objects.requireNonNull;
 
 import java.io.File;
-import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.IdentityHashMap;
@@ -56,7 +55,7 @@ import org.eclipse.aether.repository.LocalRepositoryManager;
 import org.eclipse.aether.spi.io.FileProcessor;
 import org.eclipse.aether.spi.locator.Service;
 import org.eclipse.aether.spi.locator.ServiceLocator;
-import org.eclipse.aether.transform.FileTransformer;
+import org.eclipse.aether.transform.ArtifactTransformer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -237,40 +236,32 @@ public class DefaultInstaller
     {
         LocalRepositoryManager lrm = session.getLocalRepositoryManager();
 
-        File srcFile = artifact.getFile();
-
-        Collection<FileTransformer> fileTransformers = session.getFileTransformerManager()
+        Collection<ArtifactTransformer> artifactTransformers = session.getArtifactTransformerManager()
                 .getTransformersForArtifact( artifact );
-        if ( fileTransformers.isEmpty() )
+        if ( artifactTransformers.isEmpty() )
         {
-            install( session, trace, artifact, lrm, srcFile, null );
+            install( session, trace, artifact, lrm, artifact.getFile() );
         }
         else
         {
-            for ( FileTransformer fileTransformer : fileTransformers )
+            for ( ArtifactTransformer artifactTransformer : artifactTransformers )
             {
-                install( session, trace, artifact, lrm, srcFile, fileTransformer );
+                Collection<Artifact> transformedArtifacts = artifactTransformer.transformArtifact( artifact );
+                for ( Artifact transformedArtifact : transformedArtifacts  )
+                {
+                    install( session, trace, transformedArtifact, lrm, transformedArtifact.getFile() );
+                }
             }
         }
     }
 
     private void install( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
-                          LocalRepositoryManager lrm, File srcFile, FileTransformer fileTransformer )
+                          LocalRepositoryManager lrm, File srcFile )
         throws InstallationException
     {
-        final Artifact targetArtifact;
-        if ( fileTransformer != null )
-        {
-            targetArtifact = fileTransformer.transformArtifact( artifact );
-        }
-        else
-        {
-            targetArtifact = artifact;
-        }
-
-        File dstFile = new File( lrm.getRepository().getBasedir(), lrm.getPathForLocalArtifact( targetArtifact ) );
+        File dstFile = new File( lrm.getRepository().getBasedir(), lrm.getPathForLocalArtifact( artifact ) );
 
-        artifactInstalling( session, trace, targetArtifact, dstFile );
+        artifactInstalling( session, trace, artifact, dstFile );
 
         Exception exception = null;
         try
@@ -281,38 +272,30 @@ public class DefaultInstaller
             }
 
             boolean copy =
-                "pom".equals( targetArtifact.getExtension() ) || srcFile.lastModified() != dstFile.lastModified()
+                "pom".equals( artifact.getExtension() ) || srcFile.lastModified() != dstFile.lastModified()
                     || srcFile.length() != dstFile.length() || !srcFile.exists();
 
             if ( !copy )
             {
                 LOGGER.debug( "Skipped re-installing {} to {}, seems unchanged", srcFile, dstFile );
             }
-            else if ( fileTransformer != null ) 
-            {
-                try ( InputStream is = fileTransformer.transformData( srcFile ) )
-                {
-                    fileProcessor.write( dstFile, is );
-                    dstFile.setLastModified( srcFile.lastModified() );
-                }
-            }
             else
             {
                 fileProcessor.copy( srcFile, dstFile );
                 dstFile.setLastModified( srcFile.lastModified() );
             }
 
-            lrm.add( session, new LocalArtifactRegistration( targetArtifact ) );
+            lrm.add( session, new LocalArtifactRegistration( artifact ) );
         }
         catch ( Exception e )
         {
             exception = e;
-            throw new InstallationException( "Failed to install artifact " + targetArtifact + ": " + e.getMessage(),
+            throw new InstallationException( "Failed to install artifact " + artifact + ": " + e.getMessage(),
                     e );
         }
         finally
         {
-            artifactInstalled( session, trace, targetArtifact, dstFile, exception );
+            artifactInstalled( session, trace, artifact, dstFile, exception );
         }
     }
 
diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDeployerTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDeployerTest.java
index 6664d28b..b9d8b625 100644
--- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDeployerTest.java
+++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDeployerTest.java
@@ -25,11 +25,8 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.fail;
 
-import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
@@ -58,7 +55,7 @@ import org.eclipse.aether.spi.connector.MetadataDownload;
 import org.eclipse.aether.spi.connector.MetadataUpload;
 import org.eclipse.aether.spi.connector.RepositoryConnector;
 import org.eclipse.aether.transfer.MetadataNotFoundException;
-import org.eclipse.aether.transform.FileTransformer;
+import org.eclipse.aether.transform.ArtifactTransformer;
 import org.eclipse.aether.util.artifact.SubArtifact;
 import org.junit.After;
 import org.junit.Before;
@@ -395,25 +392,20 @@ public class DefaultDeployerTest
     @Test
     public void testFileTransformer() throws Exception
     {
-        final Artifact transformedArtifact = new SubArtifact( artifact, null, "raj" );
-        FileTransformer transformer = new FileTransformer()
+        final File transformedContent = TestFileUtils.createTempFile( "transformed data" );
+        final Artifact transformedArtifact = new SubArtifact( artifact, null, "raj", transformedContent );
+        ArtifactTransformer transformer = new ArtifactTransformer()
         {
             @Override
-            public InputStream transformData( File file )
+            public Collection<Artifact> transformArtifact( Artifact artifact )
             {
-                return new ByteArrayInputStream( "transformed data".getBytes( StandardCharsets.UTF_8 ) );
-            }
-            
-            @Override
-            public Artifact transformArtifact( Artifact artifact )
-            {
-                return transformedArtifact;
+                return Collections.singleton( transformedArtifact );
             }
         };
         
-        StubFileTransformerManager fileTransformerManager = new StubFileTransformerManager();
-        fileTransformerManager.addFileTransformer( "jar", transformer );
-        session.setFileTransformerManager( fileTransformerManager );
+        StubArtifactTransformerManager artifactTransformerManager = new StubArtifactTransformerManager();
+        artifactTransformerManager.addArtifactTransformer( "jar", transformer );
+        session.setArtifactTransformerManager( artifactTransformerManager );
         
         request = new DeployRequest();
         request.addArtifact( artifact );
diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultInstallerTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultInstallerTest.java
index 0fb0e567..f45f033d 100644
--- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultInstallerTest.java
+++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultInstallerTest.java
@@ -27,12 +27,11 @@ import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 
 import org.eclipse.aether.DefaultRepositorySystemSession;
@@ -50,7 +49,7 @@ import org.eclipse.aether.internal.test.util.TestUtils;
 import org.eclipse.aether.metadata.DefaultMetadata;
 import org.eclipse.aether.metadata.Metadata;
 import org.eclipse.aether.metadata.Metadata.Nature;
-import org.eclipse.aether.transform.FileTransformer;
+import org.eclipse.aether.transform.ArtifactTransformer;
 import org.eclipse.aether.util.artifact.SubArtifact;
 import org.junit.After;
 import org.junit.Before;
@@ -424,25 +423,20 @@ public class DefaultInstallerTest
     @Test
     public void testFileTransformer() throws Exception
     {
-        final Artifact transformedArtifact = new SubArtifact( artifact, null, "raj" );
-        FileTransformer transformer = new FileTransformer()
+        final File transformedContent = TestFileUtils.createTempFile( "transformed data" );
+        final Artifact transformedArtifact = new SubArtifact( artifact, null, "raj", transformedContent );
+        ArtifactTransformer transformer = new ArtifactTransformer()
         {
             @Override
-            public InputStream transformData( File file )
+            public Collection<Artifact> transformArtifact( Artifact artifact )
             {
-                return new ByteArrayInputStream( "transformed data".getBytes( StandardCharsets.UTF_8 ) );
-            }
-            
-            @Override
-            public Artifact transformArtifact( Artifact artifact )
-            {
-                return transformedArtifact;
+                return Collections.singleton( transformedArtifact );
             }
         };
         
-        StubFileTransformerManager fileTransformerManager = new StubFileTransformerManager();
-        fileTransformerManager.addFileTransformer( "jar", transformer );
-        session.setFileTransformerManager( fileTransformerManager );
+        StubArtifactTransformerManager artifactTransformerManager = new StubArtifactTransformerManager();
+        artifactTransformerManager.addArtifactTransformer( "jar", transformer );
+        session.setArtifactTransformerManager( artifactTransformerManager );
         
         request = new InstallRequest();
         request.addArtifact( artifact );
diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/StubFileTransformerManager.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/StubArtifactTransformerManager.java
similarity index 58%
rename from maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/StubFileTransformerManager.java
rename to maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/StubArtifactTransformerManager.java
index a079a2ae..670e7812 100644
--- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/StubFileTransformerManager.java
+++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/StubArtifactTransformerManager.java
@@ -25,26 +25,26 @@ import java.util.HashSet;
 import java.util.Map;
 
 import org.eclipse.aether.artifact.Artifact;
-import org.eclipse.aether.transform.FileTransformer;
-import org.eclipse.aether.transform.FileTransformerManager;
+import org.eclipse.aether.transform.ArtifactTransformer;
+import org.eclipse.aether.transform.ArtifactTransformerManager;
 
-public class StubFileTransformerManager implements FileTransformerManager
+public class StubArtifactTransformerManager implements ArtifactTransformerManager
 {
-    private Map<String, Collection<FileTransformer>> fileTransformers = new HashMap<>();
+    private Map<String, Collection<ArtifactTransformer>> artifactTransformers = new HashMap<>();
     
     @Override
-    public Collection<FileTransformer> getTransformersForArtifact( Artifact artifact )
+    public Collection<ArtifactTransformer> getTransformersForArtifact( Artifact artifact )
     {
-        return fileTransformers.get( artifact.getExtension() );
+        return artifactTransformers.get( artifact.getExtension() );
     }
     
-    public void addFileTransformer( String extension, FileTransformer fileTransformer )
+    public void addArtifactTransformer( String extension, ArtifactTransformer fileTransformer )
     {
-        if ( !fileTransformers.containsKey( extension ) )
+        if ( !artifactTransformers.containsKey( extension ) )
         {
-            fileTransformers.put( extension, new HashSet<FileTransformer>() );
+            artifactTransformers.put( extension, new HashSet<ArtifactTransformer>() );
         }
-        fileTransformers.get( extension ).add( fileTransformer );
+        artifactTransformers.get( extension ).add( fileTransformer );
     }
 
 }
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/ArtifactUpload.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/ArtifactUpload.java
index 90323b17..fc680c51 100644
--- a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/ArtifactUpload.java
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/ArtifactUpload.java
@@ -25,7 +25,6 @@ import org.eclipse.aether.RequestTrace;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.transfer.ArtifactTransferException;
 import org.eclipse.aether.transfer.TransferListener;
-import org.eclipse.aether.transform.FileTransformer;
 
 /**
  * An upload of an artifact to a remote repository. A repository connector processing this upload has to use
@@ -34,8 +33,6 @@ import org.eclipse.aether.transform.FileTransformer;
 public final class ArtifactUpload
     extends ArtifactTransfer
 {
-    private FileTransformer fileTransformer;
-
     /**
      * Creates a new uninitialized upload.
      */
@@ -56,24 +53,6 @@ public final class ArtifactUpload
         setFile( file );
     }
 
-    /**
-     * <p>Creates a new upload with the specified properties.</p> 
-     * 
-     * <p><strong>IMPORTANT</strong> When using a fileTransformer, the
-     * content of the file is stored in memory to ensure that file content and checksums stay in sync!
-     * </p>
-     * 
-     * @param artifact The artifact to upload, may be {@code null}.
-     * @param file The local file to upload the artifact from, may be {@code null}.
-     * @param fileTransformer The file transformer, may be {@code null}.
-     */
-    public ArtifactUpload( Artifact artifact, File file, FileTransformer fileTransformer )
-    {
-        setArtifact( artifact );
-        setFile( file );
-        setFileTransformer( fileTransformer );
-    }
-
     @Override
     public ArtifactUpload setArtifact( Artifact artifact )
     {
@@ -109,29 +88,10 @@ public final class ArtifactUpload
         return this;
     }
     
-    public ArtifactUpload setFileTransformer( FileTransformer fileTransformer )
-    {
-        this.fileTransformer = fileTransformer;
-        return this;
-    }
-    
-    public FileTransformer getFileTransformer()
-    {
-        return fileTransformer;
-    }
-
     @Override
     public String toString()
     {
-        if ( getFileTransformer() != null )
-        {
-            return getArtifact() + " >>> " + getFileTransformer().transformArtifact( getArtifact() )
-                + " - " + getFile();
-        }
-        else
-        {
-            return getArtifact() + " - " + getFile();
-        }
+        return getArtifact() + " - " + getFile();
     }
 
 }