Skip to content

Integrate immutables:datatype with Plexus to remove the need for modifiable models#880

Draft
ascopes wants to merge 2 commits intomainfrom
poc/immutables-plexus-support
Draft

Integrate immutables:datatype with Plexus to remove the need for modifiable models#880
ascopes wants to merge 2 commits intomainfrom
poc/immutables-plexus-support

Conversation

@ascopes
Copy link
Copy Markdown
Owner

@ascopes ascopes commented Nov 29, 2025

This PR removes the need to use modifiable models with Plexus due to the lack of ability to handle the builder pattern.

We utilise the immutables:datatype library to generate reflective descriptors of our immutable types that support dynamically being used as builders at runtime. From this, we wrap the logic in a Plexus converter shim that can dynamically perform these operations during parameter conversion.

As a result, many of our internal types are now fully immutable and none need a duplicated "modifiable" type along side it to keep Plexus and Maven happy. This also means our APIs can now make use of the interface type in their declaration rather than the implementation.

@ascopes ascopes self-assigned this Nov 29, 2025
@ascopes ascopes added the chore General tech debt work. label Nov 29, 2025
@ascopes
Copy link
Copy Markdown
Owner Author

ascopes commented Nov 29, 2025

This is also a helpful tool for achieving GH-877, as we can now dynamically use interface types within the future sealed type adapter.

@ascopes ascopes force-pushed the poc/immutables-plexus-support branch from 9496d24 to 07b7c49 Compare November 29, 2025 16:09
@ascopes
Copy link
Copy Markdown
Owner Author

ascopes commented Nov 29, 2025

Currently blocked by a bug in the library used by maven-plugin-plugin to parse class definitions to produce the Maven Plugin metadata files.

This is awaiting a merged fix within paul-hammant/qdox#287 to be released so that apache/maven-plugin-tools#944 can be closed in the next version of maven-plugin-plugin.

[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for Protobuf Maven Plugin Parent 4.0.4-SNAPSHOT:
[INFO] 
[INFO] Protobuf Maven Plugin Parent ....................... SUCCESS [  1.882 s]
[INFO] Protobuf Maven Plugin .............................. FAILURE [  9.318 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  11.501 s (Wall Clock)
[INFO] Finished at: 2025-11-29T16:18:46Z
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-plugin-plugin:3.15.2:descriptor (default-descriptor) on project protobuf-maven-plugin: Execution default-descriptor of goal org.apache.maven.plugins:maven-plugin-plugin:3.15.2:descriptor failed: syntax error @[77,68] in file:/home/ashley/code/protobuf-maven-plugin/protobuf-maven-plugin/target/generated-sources/annotations/io/github/ascopes/protobufmavenplugin/plugins/Datatypes_MavenProtocPlugin.java -> [Help 1]                                                                                                                                  
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-plugin-plugin:3.15.2:descriptor (default-descriptor) on project protobuf-maven-plugin: Execution default-descriptor of goal org.apache.maven.plugins:maven-plugin-plugin:3.15.2:descriptor failed: syntax error @[77,68] in file:/home/ashley/code/protobuf-maven-plugin/protobuf-maven-plugin/target/generated-sources/annotations/io/github/ascopes/protobufmavenplugin/plugins/Datatypes_MavenProtocPlugin.java                                                                                              
    at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute2 (MojoExecutor.java:333)
    at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute (MojoExecutor.java:316)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:212)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:174)
    at org.apache.maven.lifecycle.internal.MojoExecutor.access$000 (MojoExecutor.java:75)
    at org.apache.maven.lifecycle.internal.MojoExecutor$1.run (MojoExecutor.java:162)
    at org.apache.maven.plugin.DefaultMojosExecutionStrategy.execute (DefaultMojosExecutionStrategy.java:39)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:159)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:105)
    at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call (MultiThreadedBuilder.java:193)
    at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call (MultiThreadedBuilder.java:180)
    at java.util.concurrent.FutureTask.run (FutureTask.java:328)
    at java.util.concurrent.Executors$RunnableAdapter.call (Executors.java:545)
    at java.util.concurrent.FutureTask.run (FutureTask.java:328)
    at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1090)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:614)
    at java.lang.Thread.run (Thread.java:1474)
Caused by: org.apache.maven.plugin.PluginExecutionException: Execution default-descriptor of goal org.apache.maven.plugins:maven-plugin-plugin:3.15.2:descriptor failed: syntax error @[77,68] in file:/home/ashley/code/protobuf-maven-plugin/protobuf-maven-plugin/target/generated-sources/annotations/io/github/ascopes/protobufmavenplugin/plugins/Datatypes_MavenProtocPlugin.java                            
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:133)
    at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute2 (MojoExecutor.java:328)
    at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute (MojoExecutor.java:316)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:212)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:174)
    at org.apache.maven.lifecycle.internal.MojoExecutor.access$000 (MojoExecutor.java:75)
    at org.apache.maven.lifecycle.internal.MojoExecutor$1.run (MojoExecutor.java:162)
    at org.apache.maven.plugin.DefaultMojosExecutionStrategy.execute (DefaultMojosExecutionStrategy.java:39)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:159)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:105)
    at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call (MultiThreadedBuilder.java:193)
    at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call (MultiThreadedBuilder.java:180)
    at java.util.concurrent.FutureTask.run (FutureTask.java:328)
    at java.util.concurrent.Executors$RunnableAdapter.call (Executors.java:545)
    at java.util.concurrent.FutureTask.run (FutureTask.java:328)
    at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1090)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:614)
    at java.lang.Thread.run (Thread.java:1474)
Caused by: com.thoughtworks.qdox.parser.ParseException: syntax error @[77,68] in file:/home/ashley/code/protobuf-maven-plugin/protobuf-maven-plugin/target/generated-sources/annotations/io/github/ascopes/protobufmavenplugin/plugins/Datatypes_MavenProtocPlugin.java                                                                                                                                             
    at com.thoughtworks.qdox.parser.impl.Parser.yyerror (Parser.java:2025)
    at com.thoughtworks.qdox.parser.impl.Parser.yyparse (Parser.java:2147)
    at com.thoughtworks.qdox.parser.impl.Parser.parse (Parser.java:2006)
    at com.thoughtworks.qdox.library.SourceLibrary.parse (SourceLibrary.java:232)
    at com.thoughtworks.qdox.library.SourceLibrary.parse (SourceLibrary.java:209)
    at com.thoughtworks.qdox.library.SourceLibrary.addSource (SourceLibrary.java:159)
    at com.thoughtworks.qdox.library.SortedClassLibraryBuilder.addSource (SortedClassLibraryBuilder.java:174)
    at com.thoughtworks.qdox.JavaProjectBuilder.addSource (JavaProjectBuilder.java:151)
    at com.thoughtworks.qdox.JavaProjectBuilder$2.visitFile (JavaProjectBuilder.java:224)
    at com.thoughtworks.qdox.directorywalker.DirectoryScanner.walk (DirectoryScanner.java:103)
    at com.thoughtworks.qdox.directorywalker.DirectoryScanner.walk (DirectoryScanner.java:91)
    at com.thoughtworks.qdox.directorywalker.DirectoryScanner.walk (DirectoryScanner.java:91)
    at com.thoughtworks.qdox.directorywalker.DirectoryScanner.walk (DirectoryScanner.java:91)
    at com.thoughtworks.qdox.directorywalker.DirectoryScanner.walk (DirectoryScanner.java:91)
    at com.thoughtworks.qdox.directorywalker.DirectoryScanner.walk (DirectoryScanner.java:91)
    at com.thoughtworks.qdox.directorywalker.DirectoryScanner.walk (DirectoryScanner.java:91)
    at com.thoughtworks.qdox.directorywalker.DirectoryScanner.scan (DirectoryScanner.java:81)
    at com.thoughtworks.qdox.JavaProjectBuilder.addSourceTree (JavaProjectBuilder.java:218)
    at com.thoughtworks.qdox.JavaProjectBuilder.addSourceTree (JavaProjectBuilder.java:205)
    at org.apache.maven.tools.plugin.extractor.annotations.JavaAnnotationsMojoDescriptorExtractor.extendJavaProjectBuilder (JavaAnnotationsMojoDescriptorExtractor.java:663)
    at org.apache.maven.tools.plugin.extractor.annotations.JavaAnnotationsMojoDescriptorExtractor.extendJavaProjectBuilder (JavaAnnotationsMojoDescriptorExtractor.java:645)
    at org.apache.maven.tools.plugin.extractor.annotations.JavaAnnotationsMojoDescriptorExtractor.scanJavadoc (JavaAnnotationsMojoDescriptorExtractor.java:257)
    at org.apache.maven.tools.plugin.extractor.annotations.JavaAnnotationsMojoDescriptorExtractor.execute (JavaAnnotationsMojoDescriptorExtractor.java:209)
    at org.apache.maven.tools.plugin.scanner.DefaultMojoScanner.populatePluginDescriptor (DefaultMojoScanner.java:94)
    at org.apache.maven.plugin.plugin.DescriptorGeneratorMojo.generate (DescriptorGeneratorMojo.java:355)
    at org.apache.maven.plugin.plugin.AbstractGeneratorMojo.execute (AbstractGeneratorMojo.java:94)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:126)
    at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute2 (MojoExecutor.java:328)
    at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute (MojoExecutor.java:316)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:212)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:174)
    at org.apache.maven.lifecycle.internal.MojoExecutor.access$000 (MojoExecutor.java:75)
    at org.apache.maven.lifecycle.internal.MojoExecutor$1.run (MojoExecutor.java:162)
    at org.apache.maven.plugin.DefaultMojosExecutionStrategy.execute (DefaultMojosExecutionStrategy.java:39)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:159)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:105)
    at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call (MultiThreadedBuilder.java:193)
    at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call (MultiThreadedBuilder.java:180)
    at java.util.concurrent.FutureTask.run (FutureTask.java:328)
    at java.util.concurrent.Executors$RunnableAdapter.call (Executors.java:545)
    at java.util.concurrent.FutureTask.run (FutureTask.java:328)
    at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1090)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:614)
    at java.lang.Thread.run (Thread.java:1474)
[ERROR] 
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException
[ERROR] 
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR]   mvn <args> -rf :protobuf-maven-plugin

@ascopes ascopes force-pushed the poc/immutables-plexus-support branch from 07b7c49 to 30bc301 Compare November 29, 2025 16:16
* runtime.
*
* @author Ashley Scopes
* @since TBC
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO(ascopes): pin this to the next minor version.

@ascopes ascopes force-pushed the poc/immutables-plexus-support branch from 30bc301 to 0a8c0ad Compare November 30, 2025 09:49
ascopes added a commit that referenced this pull request Nov 30, 2025
…types

The implementation of this will expect users to take a 'kind' attribute
on the marker for a sealed type parameter which is used via reflection
to determine the concrete implementation class. Right now, we have to
provide this info on each implementation via an annotation such that
we can influence the behaviour that will eventually be provided for us
by GH-880.

This PR also changes the documentation and plugin interface so that users
will pass in a <plugins> list containing all plugins now rather than
having four distinct parameters for the same information. The exisiting
parameters have been kept and still work the same way, but are now
undocumented in the plugin guide, and are marked as deprecated-for-removal
in v5.0.0.

With this change, we will be able to use sealed implementation kinds for
the <protoc/> parameter in future changes, further supporting GH-877.
.withCauseExactlyInstanceOf(NoSuchMethodException.class);
}

static PlexusConfiguration xml2PlexusConfiguration(String lines) {
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: move to fixture class and remove duplicates

ascopes added a commit that referenced this pull request Dec 1, 2025
…types

The implementation of this will expect users to take a 'kind' attribute
on the marker for a sealed type parameter which is used via reflection
to determine the concrete implementation class. Right now, we have to
provide this info on each implementation via an annotation such that
we can influence the behaviour that will eventually be provided for us
by GH-880.

This PR also changes the documentation and plugin interface so that users
will pass in a <plugins> list containing all plugins now rather than
having four distinct parameters for the same information. The exisiting
parameters have been kept and still work the same way, but are now
undocumented in the plugin guide, and are marked as deprecated-for-removal
in v5.0.0.

With this change, we will be able to use sealed implementation kinds for
the <protoc/> parameter in future changes, further supporting GH-877.
@ascopes ascopes force-pushed the poc/immutables-plexus-support branch 3 times, most recently from 1f58a5d to d7809c3 Compare December 9, 2025 06:42
@ascopes ascopes force-pushed the poc/immutables-plexus-support branch 3 times, most recently from ea16306 to 865975f Compare December 20, 2025 13:01
@ascopes ascopes force-pushed the poc/immutables-plexus-support branch from 865975f to acb6653 Compare December 21, 2025 10:15
@ascopes ascopes force-pushed the poc/immutables-plexus-support branch 3 times, most recently from 43bc9f9 to faef78c Compare December 22, 2025 08:33
@ascopes
Copy link
Copy Markdown
Owner Author

ascopes commented Dec 23, 2025

Hoping that apache/maven-plugin-tools#1046 will able to be merged to potentially unblock this.

@ascopes ascopes force-pushed the poc/immutables-plexus-support branch 2 times, most recently from 4df038f to a7dff44 Compare December 28, 2025 08:32
@ascopes ascopes marked this pull request as draft December 28, 2025 08:38
@ascopes ascopes force-pushed the poc/immutables-plexus-support branch 2 times, most recently from f3a2a67 to 38f11e3 Compare December 31, 2025 14:19
@ascopes ascopes force-pushed the poc/immutables-plexus-support branch 2 times, most recently from 7f9ef6b to e240b73 Compare January 5, 2026 07:13
@ascopes ascopes force-pushed the poc/immutables-plexus-support branch from e240b73 to c600301 Compare January 11, 2026 11:51
@ascopes ascopes force-pushed the poc/immutables-plexus-support branch from c600301 to b8be2eb Compare January 24, 2026 09:43
@ascopes ascopes force-pushed the poc/immutables-plexus-support branch from b8be2eb to d0afff5 Compare February 11, 2026 08:12
@ascopes ascopes force-pushed the poc/immutables-plexus-support branch 2 times, most recently from c16b64d to eec370c Compare March 2, 2026 06:59
@ascopes ascopes force-pushed the poc/immutables-plexus-support branch 2 times, most recently from c7b9100 to fb6b340 Compare March 9, 2026 08:12
@ascopes
Copy link
Copy Markdown
Owner Author

ascopes commented Mar 9, 2026

Given QDox has been deprecated, we're just waiting for a new 3.x release of Maven Plugin Tools to allow us to disable QDox scanning generated classes. This should then hopefully be mergable!

@ascopes ascopes force-pushed the poc/immutables-plexus-support branch 5 times, most recently from af93cf0 to c811e2f Compare March 22, 2026 10:15
} catch (ClassNotFoundException ex) {
return null;
} catch (ReflectiveOperationException ex) {
throw new IllegalStateException(
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace with Unchecked call introduced in GH-976.

*/
@Modifiable
@Data
@Immutable
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add checks to project structure for @Modifiable annotations if possible so we can fail builds when they are used.

*/
@Modifiable
@Data
@Immutable
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verify any changes rebased into this PR do not contain @Modifiable types.

@ascopes ascopes force-pushed the poc/immutables-plexus-support branch from c811e2f to 7735eb1 Compare April 2, 2026 07:51
@ascopes ascopes force-pushed the poc/immutables-plexus-support branch 4 times, most recently from b9f841f to 015908e Compare April 9, 2026 15:37
ascopes added 2 commits April 9, 2026 16:46
…ype duplicates

Implement initial POC for hooking Plexus into immutable builder classes

Use fix from paul-hammant/qdox#271 temporarily to work around apache/maven-plugin-tools#944

Fix test compilation failure

Fix ImmutablesDataPlexusConverter to handle stdlib/primitive types correctly

Start writing unit tests for plexus converter for Immutables types

Update logic in plexus converters

Use Datatypes rather than Data for immutables

Ran into immutables/immutables#1608 when initialising the data type descriptors.

Add missing test case for immutables/immutables#1608

Update Plexus converter to use weak references to class types

Move test data to subpackage

Fix issues with nested type handling, add new test cases

Suppress testdata in Checkstyle
@ascopes ascopes force-pushed the poc/immutables-plexus-support branch from 015908e to 87a0da7 Compare April 9, 2026 15:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore General tech debt work.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant