gnodet-bot commented on code in PR #13722:
URL: https://github.com/apache/maven/pull/13722#discussion_r4389615130


##########
api/maven-api-spi/src/main/java/org/apache/maven/api/services/model/ModelProcessor.java:
##########
@@ -34,6 +37,15 @@
  */
 public interface ModelProcessor {
 
+    /**
+     * Option key for passing an {@link XmlReaderRequest.Transformer} through 
the options map.
+     * When present, {@code DefaultModelProcessor} uses this transformer for 
XML parsing instead
+     * of the default {@code ModelInterningTransformer}.
+     *
+     * @since 4.0.0
+     */
+    String TRANSFORMER = "transformer";

Review Comment:
   💡 **[MEDIUM] SPI Javadoc references implementation classes**
   
   The Javadoc for the `TRANSFORMER` constant names two implementation classes:
   
   > When present, `DefaultModelProcessor` uses this transformer … instead of 
the default `ModelInterningTransformer`.
   
   Both `DefaultModelProcessor` and `ModelInterningTransformer` are internal 
implementation details (`impl/maven-impl`), not part of the SPI contract. SPI 
Javadoc should describe behavior in terms of the abstraction only. Referencing 
concrete impl classes tightly couples the contract to the current 
implementation, makes future refactoring harder, and may mislead third-party 
`ModelProcessor` implementors into thinking they must replicate this behavior.
   
   Suggested rewrite:
   
   ```suggestion
       /**
        * Option key for passing an {@link XmlReaderRequest.Transformer} 
through the options map.
        * When present, the processor should use this transformer for XML 
parsing instead
        * of any default transformer it would otherwise apply.
        *
        * @since 4.0.0
        */
       String TRANSFORMER = "transformer";
   ```



##########
impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelProcessor.java:
##########
@@ -114,21 +118,112 @@ public Model read(XmlReaderRequest request) throws 
IOException {
                 }
             }
             try {
-                return doRead(request);
-            } catch (IOException | XmlReaderException e) {
+                return doRead(source, options);
+            } catch (ModelParserException e) {
                 if (!exceptions.isEmpty()) {
-                    IOException ioException = new 
IOException(buildDetailedErrorMessage(pomFile, exceptions, e));
-                    exceptions.values().forEach(ioException::addSuppressed);
-                    ioException.addSuppressed(e);
-                    throw ioException;
+                    ModelParserException mpe =
+                            new 
ModelParserException(buildDetailedErrorMessage(pomFile, exceptions, e), e);
+                    exceptions.values().forEach(mpe::addSuppressed);
+                    mpe.addSuppressed(e);
+                    throw mpe;
                 }
                 throw e;
             }
         } else {
-            return doRead(request);
+            return doRead(source, options);
         }
     }
 
+    /**
+     * Implements the deprecated bridge for backward compatibility.
+     * Delegates to {@link #read(Source, Map)}, then re-throws {@link 
XmlReaderException}
+     * or {@link IOException} from the cause when possible.
+     *
+     * @deprecated Use {@link #read(Source, Map)} instead.
+     */
+    @Deprecated(since = "4.0.0")
+    @Override
+    public Model read(XmlReaderRequest request) throws IOException, 
XmlReaderException {
+        Objects.requireNonNull(request, "request cannot be null");
+        Source source = toSource(request);
+        try {
+            return read(source, Map.of(ModelParser.STRICT, 
request.isStrict()));

Review Comment:
   ⚠️ **[HIGH] Deprecated bridge drops transformer from `XmlReaderRequest`**
   
   The deprecated `read(XmlReaderRequest)` bridge at line 150 builds its 
options map with only `ModelParser.STRICT`:
   
   ```java
   return read(source, Map.of(ModelParser.STRICT, request.isStrict()));
   ```
   
   Any transformer set via `request.getTransformer()` is silently dropped. 
Callers using the deprecated method with a custom transformer will silently get 
the default `ModelInterningTransformer` instead — a behavioral regression with 
no warning.
   
   Fix: include the transformer in the delegating call:
   
   ```suggestion
               return read(source, request.getTransformer() != null
                       ? Map.of(ModelParser.STRICT, request.isStrict(), 
ModelProcessor.TRANSFORMER, request.getTransformer())
                       : Map.of(ModelParser.STRICT, request.isStrict()));
   ```



##########
impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSuperPomProvider.java:
##########
@@ -61,16 +65,42 @@ private Model readModel(String version, String v) {
             throw new IllegalStateException("The super POM " + resource + " 
was not found"
                     + ", please verify the integrity of your Maven 
installation");
         }
-        try (InputStream is = url.openStream()) {
-            String modelId =
-                    "org.apache.maven:maven-api-impl:" + 
getImplementationVersion(getClass()) + ":super-pom-" + version;
-            return modelProcessor.read(XmlReaderRequest.builder()
-                    .modelId(modelId)
-                    .location(url.toExternalForm())
-                    .inputStream(is)
-                    .strict(false)
-                    .build());
-        } catch (IOException e) {
+        String modelId =
+                "org.apache.maven:maven-api-impl:" + 
getImplementationVersion(getClass()) + ":super-pom-" + version;
+        ModelSource source = new ModelSource() {
+            @Override
+            public Path getPath() {
+                return null;
+            }
+
+            @Override
+            public InputStream openStream() throws IOException {
+                return url.openStream();
+            }
+
+            @Override
+            public String getLocation() {
+                return url.toExternalForm();
+            }
+
+            @Override
+            public Source resolve(String relative) {
+                return null;
+            }
+
+            @Override
+            public ModelSource resolve(ModelLocator modelLocator, String 
relative) {

Review Comment:
   🔧 **[LOW] Anonymous `ModelSource` duplicates boilerplate from 
`DefaultModelProcessor.toSource()`**
   
   This anonymous `ModelSource` implementation (lines 70–96) is ~25 lines of 
structural boilerplate that mirrors the `toSource()` factory in 
`DefaultModelProcessor`. Consider extracting a small package-private 
`UrlModelSource` record or static factory to reduce duplication and make the 
pattern reusable:
   
   ```java
   // e.g. in a shared utility or within DefaultModelProcessor
   static ModelSource urlModelSource(URL url, String modelId) { ... }
   ```
   
   This isn't blocking, but consolidating now while the refactoring is fresh 
avoids accumulating duplicate implementations.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to