You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@maven.apache.org by "ascopes (via GitHub)" <gi...@apache.org> on 2025/11/03 07:22:51 UTC

[I] Maven 4: first class support for sealed types in parameter configuration. [maven]

ascopes opened a new issue, #11378:
URL: https://github.com/apache/maven/issues/11378

   ### New feature, improvement proposal
   
   Hello.
   
   Proposing that given Maven 4 will baseline to Java 17, sealed classes get a simplified interface for implementation discovery during the parameter convertion process.
   
   ## Aims
   
   - Reduce boilerplate for users.
   - Allow polymorphic conversion of sealed types using intrinsics
   - Allow further documentation generation automatically from sealed types.
   
   ## Sealed type handling
   
   Effectively, suppose I have the following Mojo:
   
   ```java
   @Mojo(...)
   public class MyMojo extends ... {
   
     @Parameter
     ThirdPartyArtifact artifact;
   
     ...
   }
   ```
   
   Now, let's assume `ThirdPartyArtifact` is sealed:
   
   ```java
   public sealed interface ThirdPartyArtifact {
     public final class MavenArtifact implements ThirdPartyArtifact { ... }
   
     public final class SystemPathArtifact implements ThirdPartyArtifact { ... }
   
     public final class LocalPathArtifact implements ThirdPartyArtifact { ... }
   
     public final class RemoteUrlArtifact implements ThirdPartyArtifact { ... }
   }
   ```
   
   Currently, my understanding is that the user would have to provide the canonical class name and package to the `implementation` attribute in their XML configuration, to avoid ambiguity.
   
   Given the types are sealed, we should be able to query `Class#getPermittedSubclasses()` to get all implementations. This would in theory allow us to perform this class lookup based on just the class simple name, allowing a user to simplify configuration from...
   
   ```xml
   <configuration>
     <artifact implementation="io.github.ascopes.myplugin.models.MavenArtifact.SystemPathArtifact">
       <name>gcc</name>
     </artifact>
   </configuration>
   ```
   
   ...to just...
   
   ```xml
   <configuration>
     <artifact implementation="SystemPathArtifact">
       <name>gcc</name>
     </artifact>
   </configuration>
   ```
   
   ...which is far less verbose and far more user-friendly. 
   
   ## Possible implementation
   
   A new converter could be added to the Plexus context by default with the following implementation:
   
   ```java
   public class SealedTypeConverter extends AbstractBasicConverter {
   
     @Override
     public boolean canConvert(Class<?> cls) {
       return cls.isSealed();
     }
   
     @Override
     public Object fromConfiguration(
         ConverterLookup lookup,
         PlexusConfiguration configuration,
         Class<?> type,
         Class<?> enclosingType,
         ClassLoader classLoader,
         ExpressionEvaluator evaluator
     ) throws ComponentConfigurationException {
       if (configuration.getChildCount() == 0) {
         return null;
       }
   
       var hint = configuration.getAttribute("implementation");
   
       var implementationClass = Stream
           .of(type.getPermittedSubclasses())
           .sorted(Class::getName)
           .filter(cls -> getPermittedClassNames(cls)
               .anyMatch(name -> name.equals(hint))
           .findFirst();
   
       if (implementationClass.isNotPresent()) {
         throw new ComponentConfigurationException(...);
       }
   
       return converterLookup.lookupConverterFromType(implementationClass.get())
           .fromConfiguration(...);
     }
   
     private Stream<String> getPermittedClassNames(Class<?> type) {
       var canonicalNames = Stream.of(
           type.getName(),
           type.getSimpleName()
       );
   
       var customHints = ofNullable(type.getAnnotation(SealedTypeHint.class)
           .map(SealedTypeHint::value)
           .stream()
           .flatMap(Stream::of);
   
       return Stream.concat(canonicalNames, customHints);
     }
   }
   
   ## Addition of metadata to `@Parameter`
   
   It would be sensible to add an attribute to `@Parameter` to allow the specification of the default implementation type to consider if information is not provided. I'd envison this being allowed for both sealed and non-sealed types, for example:
   
   ```java
   @interface Parameter {
     ...
   
     Class<?> defaultImplementation() default void.class;
   }
   ```
   
   ```java
   class MyMojo extends ... {
     @Parameter(defaultImplementation = MavenArtifact.class)
     ThirdPartyArtifact artifact;
   
     // Also useful for cases where code is generated via an annotation processor.
     // Consider the immutables library:
     @Parameter(defaultImplementation = MutableSourceListing.class)
     SourceListing source;
   }
   ```
   
   ## Caveats and possible improvements
   
   A caveat to this would be if there is more than one implementor with the same name. Aside from being a very poor design decision, this could be worked around by either raising a warning/exception, or providing the developer with a way of "tagging" implementation names to the sealed class implementations via an annotation.
   
   The annotation for doing this could
   be the following:
   
   ```java
   @Retention(RUNTIME)
   @Target({TYPE, RECORD})
   public @interface SealedTypeHint {
     String[] value();
   }
   ```
   
   ...this would allow defining my example from earlier like so:
   
   ```java
   public sealed interface ThirdPartyArtifact {
     @SealedTypeHint("maven")
     public final class MavenArtifact implements ThirdPartyArtifact { ... }
   
     @SealedTypeHint("system-path")
     public final class SystemPathArtifact implements ThirdPartyArtifact { ... }
   
     @SealedTypeHint("local-path")
     public final class LocalPathArtifact implements ThirdPartyArtifact { ... }
   
     @SealedTypeHint("remote")
     public final class RemoteUrlArtifact implements ThirdPartyArtifact { ... }
   }
   ```
   
   ...enabling the XML example to be just...
   
   ```xml
   <configuration>
     <artifact implementation="system-path">
       <name>gcc</name>
     </artifact>
   </configuration>
   ```
   
   One other caveat may be the use of `non-sealed` implementation types. However, in this case, the default behaviour of `implementation` should still be allowed for backwards compatibility.
   
   ### Further possible improvements
   
   - Records could be supported for deserialization via Plexus to allow developers to create concise parameter definitions.
   - Documentation could be generated from the knowledge of the sealed types in `maven-plugin-plugin` to avoid developers having to manually document supported types.
   - The `maven-plugin-plugin` could configure the generated XSD schema to have knowledge of the known permitted types for the parameter, allowing IDEs to provide clear linting and autocomplete for polymorphic types without
   having to perform expensive classpath analysis of the plugin and dependency tree.
       - This implementation would be compatible with other schema formats like JsonSchema, should Maven decide to allow non-XML configuration in the future.
   - The `@SealedTypeHint` _in theory_ could be changed to be just a regular `@TypeHint` or leverage similar Java EE/Jakarta EE metadata annotations for the same purpose. This would potentially require costly classpath scanning though which may hinder startup execution times for plugins. In theory though this information may be possible to collect when `maven-plugin-plugin` is run.
   
   ## Workarounds
   
   Right now in Maven 3, parameters have to have a clear type or rely on the user giving a fully qualified canonical class name. This contributes to the outdated archetype that Maven is overly verbose for new users, which can hinder adoption.
   
   Polymorphic types have to be documented explicitly by the developer rather than being generated from JavaDocs when a type is sealed, which leads to documentation mistakes and inconsistencies. Many plugins just do not document this sort of thing properly at all, requiring users of plugins to have to read the source code to have any idea how to configure this sort of thing properly.


-- 
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: issues-unsubscribe@maven.apache.org.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [I] Maven 4: first class support for sealed types in parameter configuration. [maven]

Posted by "Will-thom (via GitHub)" <gi...@apache.org>.
Will-thom commented on issue #11378:
URL: https://github.com/apache/maven/issues/11378#issuecomment-4492344240

   Hi guys and @gnodet 
   
   I opened a PR with a partial implementation for this proposal: https://github.com/apache/maven/pull/12117
   
   The PR focuses on the smallest Maven core change first: for Maven 4 enhanced parameter configuration, sealed parameter types can now resolve `implementation` hints by permitted subclass simple name, while keeping fully-qualified implementation hints working.
   
   Covered in the PR:
   - `implementation="LocalArtifact"` resolves against `sealed` permitted subclasses.
   - Fully-qualified implementation hints keep working.
   - Unknown simple hints fail with a clear error.
   - Unit coverage in `DefaultBeanConfiguratorTest`.
   - End-to-end Maven 4 plugin IT for GH-11378.
   
   Not covered yet:
   - A new `@Parameter(defaultImplementation = ...)` API.
   - Custom type hint annotations such as `@SealedTypeHint`.
   - Generated plugin documentation/XSD improvements.
   
   I kept this intentionally narrow to make the first step easier to review and to avoid introducing new public API before there is maintainer feedback.


-- 
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: issues-unsubscribe@maven.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [I] Maven 4: first class support for sealed types in parameter configuration. [maven]

Posted by "gnodet (via GitHub)" <gi...@apache.org>.
gnodet closed issue #11378: Maven 4: first class support for sealed types in parameter configuration.
URL: https://github.com/apache/maven/issues/11378


-- 
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: issues-unsubscribe@maven.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org