And one more thing....

Migrate off from legacy Plexus XML
src/main/resources/META-INF/plexus/components.xml

and use JSR330 instead:
- add javax.inject:javax.inject:1 as dependency
- annotate your imple with @Singleton/@Named( "default" )
- use sisu-maven-plugin in the build to index annotated classes

Thanks all
T

On Wed, Jun 29, 2022 at 1:05 PM Tamás Cservenák <ta...@cservenak.net> wrote:

> Also, if you'd not use oldie EventSpy, but
> AbstractMavenLifecycleParticipant instead, you'd gain access to session,
> and would become even simpler:
> just stick something with specific (to your extension, like G:A) key and
> dummy value (Boolean,TRUE) into session.
> And then you know: if that key IS PRESENT when init, you was not the first
> instance of extension to init.
>
> T
>
> On Wed, Jun 29, 2022 at 1:01 PM Tamás Cservenák <ta...@cservenak.net>
> wrote:
>
>> Howdy,
>>
>> First of all, if you alter the maven classpath, there is not much Maven
>> itself can do (as it happens before maven happens). How are conflicting
>> classes handled depends on Java, not Maven.
>>
>> So, I'd really just neglect the use of `maven.ext.class.path` (or adding
>> things to lib/ext). Using these you (or user) is tampering with very
>> internals, and should be really aware of what is being done.
>>
>> Hence, I went with the 2nd case, the `.mvn/extensions.xml` and used this
>> one:
>> <?xml version="1.0" encoding="UTF-8"?>
>> <extensions>
>>     <extension>
>>         <groupId>org.example</groupId>
>>         <artifactId>double-core-bindings-override</artifactId>
>>         <version>1.0</version>
>>     </extension>
>>     <extension>
>>         <groupId>org.example</groupId>
>>         <artifactId>double-core-bindings-override</artifactId>
>>         <version>2.0</version>
>>     </extension>
>> </extensions>
>>
>> And to my biggest surprise, Maven did load both extensions just fine
>> (based on file order, if you make it 2.0, then 1.0, it will load in that
>> order).
>>
>> [cstamas@urnebes DoubleCoreBindingsOverride]$ ./mvnw validate
>> [INFO] Found MyExtension in realm
>> 'coreExtension>org.example:double-core-bindings-override:1.0'
>> [INFO] Found MyExtension in realm
>> 'coreExtension>org.example:double-core-bindings-override:2.0'
>> [INFO] Inside MyExtension#init for extension loaded in realm
>> 'coreExtension>org.example:double-core-bindings-override:2.0'
>> [INFO] Instantiating MyPluginManager for extension loaded in realm
>> 'coreExtension>org.example:double-core-bindings-override:2.0'
>> [INFO] Using the MavenPluginManager 'MyPluginManager' from realm '
>> coreExtension>org.example:double-core-bindings-override:2.0'
>> [INFO] Inside MyExtension#init for extension loaded in realm
>> 'coreExtension>org.example:double-core-bindings-override:1.0'
>> [INFO] Using the MavenPluginManager 'MyPluginManager' from realm '
>> coreExtension>org.example:double-core-bindings-override:2.0'
>> [INFO] Scanning for projects...
>> [INFO]
>> [INFO] -------------< org.example:double-core-bindings-override
>> >--------------
>> [INFO] Building DoubleCoreBindingsOverride reproducer 2.0
>> [INFO] --------------------------------[ jar
>> ]---------------------------------
>> [INFO]
>> ------------------------------------------------------------------------
>> [INFO] BUILD SUCCESS
>> [INFO]
>> ------------------------------------------------------------------------
>> [INFO] Total time:  0.037 s
>> [INFO] Finished at: 2022-06-29T12:51:56+02:00
>> [INFO]
>> ------------------------------------------------------------------------
>> [cstamas@urnebes DoubleCoreBindingsOverride]$
>>
>> ===
>>
>> All in all, to prevent this (obviously user mistake), I'd not think too
>> much about it: maybe just create a "known" file during init
>> - if file does not exist, write an extension version into it
>> - if exists, read its content and if matches extension version, all ok,
>> otherwise just explode?
>> - delete the file in close (when session ends)
>>
>> This way you will ensure that IF there was a user mistake (double
>> configured your extension w/ different versions), it will not end up in an
>> inconsistent build, but the user is forced to fix it?
>> You could also just create a file (and neglect version), as if file was
>> created during init, your 2nd instance should fail (as it means there are
>> more than one instances of your extension present).
>>
>>
>> HTH
>> T
>>
>>
>> On Tue, Jun 28, 2022 at 4:31 PM François Guillot <
>> francoisguillo...@gmail.com> wrote:
>>
>>> Hi again
>>>
>>> I can't go into details because it's a proprietary extension, but we need
>>> to change the behaviour of
>>> - *DefaultMavenPluginManager*: we need to intercept calls to Mojo#execute
>>> so here we proxy the Mojo class that is created from the mojoInterface
>>> with
>>> some custom stuffs
>>> - *DefaultBuildPluginManager*: we decorate the #executeMojo with some
>>> custom calls to internal classes of ours
>>>
>>> For now, all is good. I just realized the overridden components might not
>>> come from the expected extension so let's say we are theorizing about
>>> some
>>> possible future binary breakage.
>>>
>>> You can find attached a small reproducer:
>>>
>>> https://drive.google.com/file/d/1M-wfS8E_VgHF6qd1CthkHQuzkYEMqNe1/view?usp=sharing
>>>
>>> (I could not attach the zip directly to Gmail ...)
>>>
>>> To reproduce, once unzipped:
>>> - ./mvnw clean install => install 1.0 in your local repo
>>> - change version to 2.0 in pom.xml
>>> - ./mvnw clean install => install 2.0 in your local repo
>>> - add ".mvn/extensions.xml" with
>>> ----------
>>> <?xml version="1.0" encoding="UTF-8"?>
>>> <extensions>
>>> <extension>
>>> <groupId>org.example</groupId>
>>> <artifactId>double-core-bindings-override</artifactId>
>>> <version>1.0</version>
>>> </extension>
>>> </extensions>
>>> ----------
>>> - execute ./mvnw validate
>>>
>>> -Dmaven.ext.class.path=${HOME}/.m2/repository/org/example/double-core-bindings-override/2.0/double-core-bindings-override-2.0.jar
>>>
>>> You should then see sth like
>>>
>>> [INFO] Found MyExtension in realm 'maven.ext'
>>> [INFO] Found MyExtension in realm
>>> 'coreExtension>org.example:double-core-bindings-override:2.0'
>>> [INFO] Inside MyExtension#init for extension loaded in realm
>>> 'coreExtension>org.example:double-core-bindings-override:2.0'
>>> [INFO] Instantiating MyPluginManager for extension loaded in realm
>>> 'coreExtension>org.example:double-core-bindings-override:2.0'
>>> [INFO] Using the MavenPluginManager 'MyPluginManager' from realm '
>>> coreExtension>org.example:double-core-bindings-override:2.0'
>>> [INFO] Inside MyExtension#init for extension loaded in realm 'maven.ext'
>>> [INFO] Using the MavenPluginManager 'MyPluginManager' from realm '
>>> coreExtension>org.example:double-core-bindings-override:2.0'
>>>
>>> The extension from maven.ext (extension version 1.0) is found and
>>> injected
>>> The extension from extensions.xml (extension version 2.0) is found and
>>> injected
>>> The #init for the 2.0 extension is called
>>> The #init for the 1.0 extension is called (maven.ext)
>>> Only the MyPluginManager instance from extension 2.0 is present, even
>>> when
>>> called from the extension 1.0.
>>>
>>> I understand why this happens but this is potentially dangerous.
>>> I tried various ways to avoid that from happening but failed.
>>> Hence my question, is there a better way to declare core overrides than
>>> in
>>> components.xml ?
>>>
>>>
>>> Also, side question, when I'm changing the META-INF/maven/extension.xml
>>> to
>>> contain
>>>
>>> <exportedPackages>
>>>     <exportedPackage>org.example</exportedPackage>
>>> </exportedPackages>
>>>
>>> Then, the problem 'goes away':
>>> [INFO] Found MyExtension in realm
>>> 'coreExtension>org.example:double-core-bindings-override:2.0'
>>> [INFO] Found MyExtension in realm
>>> 'coreExtension>org.example:double-core-bindings-override:2.0'
>>> [INFO] Inside MyExtension#init for extension loaded in realm
>>> 'coreExtension>org.example:double-core-bindings-override:2.0'
>>> [INFO] Instantiating MyPluginManager for extension loaded in realm
>>> 'coreExtension>org.example:double-core-bindings-override:2.0'
>>> [INFO] Using the MavenPluginManager 'MyPluginManager' from realm '
>>> coreExtension>org.example:double-core-bindings-override:2.0'
>>> [INFO] Inside MyExtension#init for extension loaded in realm
>>> 'coreExtension>org.example:double-core-bindings-override:2.0'
>>> [INFO] Using the MavenPluginManager 'MyPluginManager' from realm '
>>> coreExtension>org.example:double-core-bindings-override:2.0'
>>>
>>> Can you explain what exactly happens in this case ?
>>> Maybe I could leverage that to solve my double application problem ?
>>>
>>> many thanks,
>>> François
>>>
>>>
>>> Le mar. 28 juin 2022 à 13:26, Tamás Cservenák <ta...@cservenak.net> a
>>> écrit :
>>>
>>> > In other words, why do you need to override MavenPluginManager in
>>> several
>>> > different ways?
>>> > (or we just theoretize, about some possible future binary breakage?)
>>> >
>>> > T
>>> >
>>> > On Tue, Jun 28, 2022 at 1:12 PM Tamás Cservenák <ta...@cservenak.net>
>>> > wrote:
>>> >
>>> > > Ok,
>>> > >
>>> > > best would be to create then a reproducer, but have to note:
>>> > > while Maven can "protect" (warn) about duplicate/wrong plugin
>>> > > declarations, as "lower" we go (and extensions, especially when you
>>> throw
>>> > > things into lib/ext) are earlier and earlier on the bootstrap of
>>> Maven,
>>> > and
>>> > > it cannot do much there...
>>> > > Hence, while Maven tries its best to protect you (users) from
>>> mistakes,
>>> > it
>>> > > cannot always do it, especially when things are just added to
>>> > classpath....
>>> > >
>>> > > Also, non-backward compatible with your implementation of the Maven
>>> > > component (interface) of MavenPluginManager?
>>> > > Again, I'd really like to see what happens here, what the extension
>>> > intent
>>> > > is, not only "reproducer" for "multiple extensions override the same
>>> > > component".
>>> > >
>>> > > Tamas
>>> > >
>>> > > On Tue, Jun 28, 2022 at 12:32 PM François Guillot <
>>> > > francoisguillo...@gmail.com> wrote:
>>> > >
>>> > >> Hi Tamás,
>>> > >>
>>> > >> I have one extension (say 'MyExtension'), that declares a binding
>>> > override
>>> > >> for MavenPluginManager.
>>> > >> MyExtension is not supposed to be applied several times per build,
>>> and
>>> > I'm
>>> > >> trying my best to keep only one of them 'active' if that happens.
>>> > >> Given there are various ways to declare extensions
>>> > ('.mvn/extensions.xml',
>>> > >> 'lib/ext' in Maven installation, '-Dmaven.ext.class.path'), the
>>> order of
>>> > >> applications of extensions, the fact they are not loaded in the same
>>> > >> classloader makes it a bit hard to do.
>>> > >> But I'm managing that.
>>> > >> The only thing I'm not managing 'in code' is controlling which
>>> extension
>>> > >> wins and overrides the Maven core bindings.
>>> > >>
>>> > >> I'm thinking ahead if at some point I'm making a non backward
>>> compatible
>>> > >> change (wrt to my extension code) in my implementation of
>>> > >> MavenPluginManager, than I can be in trouble, where the 'chosen'
>>> > >> MavenPluginManager implementation will not be compatible with the
>>> > 'chosen'
>>> > >> MyExtension.
>>> > >>
>>> > >> I can't share the code of my extension, but I could produce a little
>>> > >> reproducer with a noop extension to show you what I mean.
>>> > >>
>>> > >> Le mar. 28 juin 2022 à 11:45, Tamás Cservenák <ta...@cservenak.net>
>>> a
>>> > >> écrit :
>>> > >>
>>> > >> > Howdy,
>>> > >> >
>>> > >> > I am a bit uncertain if I correctly understand your problem: so
>>> you
>>> > have
>>> > >> > several MavenPluginManager implementations in several extensions,
>>> and
>>> > >> those
>>> > >> > extensions are not compatible with each other?
>>> > >> >
>>> > >> > Could we step back a little and could you explain what your
>>> extension
>>> > is
>>> > >> > doing? Best if you could show us some sources?
>>> > >> >
>>> > >> > HTH
>>> > >> > Tamas
>>> > >> >
>>> > >> >
>>> > >> >
>>> > >> > On Tue, Jun 28, 2022 at 10:18 AM François Guillot <
>>> > >> > francoisguillo...@gmail.com> wrote:
>>> > >> >
>>> > >> > > Hi,
>>> > >> > >
>>> > >> > > I need to override some default Maven bindings in my custom
>>> > extension,
>>> > >> > for
>>> > >> > > instance "org.apache.maven.plugin.MavenPluginManager"
>>> > >> > >
>>> > >> > > I'm doing this by providing a "META-INF/plexus/components.xml"
>>> in my
>>> > >> > > extension's jar with
>>> > >> > > <<
>>> > >> > >
>>> > >> > > <?xml version="1.0" encoding="UTF-8"?>
>>> > >> > > <component-set>
>>> > >> > >   <components>
>>> > >> > >     <component>
>>> > >> > >       <role>org.apache.maven.plugin.MavenPluginManager</role>
>>> > >> > >
>>>  <implementation>com.acme.MyMavenPluginManager</implementation>
>>> > >> > >
>>> > >> > >     </component>
>>> > >> > >   </components>
>>> > >> > > </component-set>
>>> > >> > >
>>> > >> > > >>
>>> > >> > >
>>> > >> > > This works fine, but this has limitations.
>>> > >> > > If for some reasons, my extension is applied twice or more to
>>> the
>>> > >> build,
>>> > >> > > then all of these applications will override the Maven core
>>> binding.
>>> > >> My
>>> > >> > > finding is that the last application wins.
>>> > >> > > This can be problematic if the user is applying several
>>> _versions_
>>> > of
>>> > >> my
>>> > >> > > extension (probably unknowingly), because the overridden
>>> > >> > MavenPluginManager
>>> > >> > > might be coming from a version of my extension that is not
>>> > compatible
>>> > >> > with
>>> > >> > > the code in the other one.
>>> > >> > >
>>> > >> > > Is there a more programmatic way to override Maven core
>>> bindings,
>>> > that
>>> > >> > > would allow me to decide whether a given extension should
>>> perform
>>> > the
>>> > >> > > override or not ?
>>> > >> > >
>>> > >> >
>>> > >>
>>> > >
>>> >
>>>
>>

Reply via email to