I've been working on this part time over the weekends lately, and after exploring a bit of Guice and CDI, I've come to the conclusion that if we were to rebase the plugin system on any annotation style, it seems as though CDI provides a fairly good set of extensions to javax.inject which would potentially work well with our existing annotations for backward compatibility. I wouldn't want to introduce an actual dependency on it, but a plugin SPI inspired by it could potentially work. A nice advantage to adopting a CDI-like system is that it should be simpler to use by other developers who aren't familiar with our custom framework.
General overview of potential changes: * In addition to scopes and qualifiers, introduce stereotype annotations which are used for combining multiple annotations. This will help a lot in making old annotations still work properly. * Introduce a Produces and Disposes annotation that work similarly to CDI. * Introduce a PostConstruct and PreDestroy annotation because later versions of Java removed them from the base JDK (they're in a separate module from java.base), and javax.inject is supposed to support those annotations. * Introduce a "Configuration" scope which lives for the life of a configuration. This would essentially replace the concept of a "core" plugin category as they map to the lifecycle of a configuration source. * Use the "Singleton" scope for anything we'd want to live for the entire application instance (generally replaces use of system property singletons where possible). * Integrate some common scopes like request-scoped, session-scoped, etc., to allow for a more pluggable system for introducing scopes for Lookups or other plugins. * Use the PostConstruct/PreDestroy callbacks to replace initialize and destroy methods in plugins. This might work well toward generic lifecycle management which is currently done ad hoc. * I have a vague notion that a "LogEvent" scope would be really neat, but such a system would likely not work well with GC-free code, so I'm not really considering this one at the moment. * PluginAttribute/PluginBuilderAttribute/PluginElement/PluginValue all become stereotype qualifiers with some annotation compatibility checks to support old annotations. * PluginFactory becomes a stereotype producer annotation. * PluginBuilderFactory (previously deleted) would also be a stereotype producer annotation. One thing I'm experimenting with right now that should really help inform me whether or not this effort will be worth it is breaking this down into an SPI that will have two default implementations: one based on runtime reflection, and another based on generated code from the annotation processor (a more advanced version of the existing PluginService code generator). I hope to avoid the use of actual reflection APIs in the generated code to more easily support GraalVM as well as to hopefully offload a bit of the reflective initialization to compile-time rather than at runtime (fairly useful for microservices where startup time is more important). I do have an overarching purpose behind all this: I'd like to dramatically reduce the tight coupling between Configuration, Node, and plugin classes. Some of this is in the form of a more generic dependency injection API to avoid the need for manually calling Configuration methods in plugin factories. Another is to make various services provided by Configuration to instead be injected directly as parameters to the plugin factories. Reducing the coupling between plugins and other running parts of the system should help reduce the complexity of many tests as well, and it may also help reduce the time taken running tests, though that will still likely be affected by the various integration tests regardless. On Wed, 9 Oct 2019 at 16:52, Matt Sicker <boa...@gmail.com> wrote: > > Part of this is to make it simpler to access globally configured > things without having to pass around a Configuration everywhere. If > plugins can declare the explicit parts of the API they need access to > rather than the full Configuration, that should make tests a bit > lighter and easier to write. > > On Wed, 9 Oct 2019 at 16:11, Ralph Goers <ralph.go...@dslextreme.com> wrote: > > > > FWIW, I don’t think @Inject is a good replacement for @PluginFactory. > > @Inject is essentially the same as @Autowired. It should be placed on > > fields where you want the implementation to be injected. @Inject specified > > on a method implies that the method parameters should be injected. I don’t > > think that is what you are intending. > > > > Ralph > > > > > On Oct 9, 2019, at 1:38 PM, Ralph Goers <ralph.go...@dslextreme.com> > > > wrote: > > > > > > Ok, but given @Scope and @Qualifier can only be used to annotate the > > > existing PluginElement, PluginAttribute and PluginValue annotations I am > > > not sure what they buy you. They can’t be used to replace the existing > > > annotations as they are only allowed to be used on annotation > > > declarations. I agree that @PluginConfiguration is somewhat redundant. > > > All we are really doing with it is saying that the existing Configuration > > > object should be passed to the method. Using @PluginConfiguration for > > > that is easy but using @Inject as an indicator and checking the type of > > > the parameter could just as easily be done. > > > > > > I guess I would like to see what you think an example plugin would look > > > like before going further. > > > > > > Ralph > > > > > > > > > > > >> On Oct 9, 2019, at 11:46 AM, Matt Sicker <boa...@gmail.com> wrote: > > >> > > >> I want to make it simpler to write plugins. Increase testability, reuse > > >> more standard APIs that others would be more familiar with (easier > > >> onboarding), and make it simpler to implement some tangentially related > > >> feature ideas. > > >> > > >> As for the builder versus factory annotation, there was already special > > >> support for collections and maps that weren’t explicit annotations, so > > >> determining what to do based on the return type of the factory method was > > >> already an established idea. I think it made sense to combine them all > > >> into > > >> @PluginFactory, and because of that, I noticed the correspondence between > > >> that and @Inject. > > >> > > >> On Wed, Oct 9, 2019 at 13:28, Ralph Goers <ralph.go...@dslextreme.com> > > >> wrote: > > >> > > >>> I still don’t understand what the benefit is. IIUC your plan is to add > > >>> the > > >>> @Scope and @Qualifier annotations to the @PluginElement and > > >>> @PluginAttribute. If that somehow helps, great, as it is will be > > >>> invisible > > >>> to plugin developers. > > >>> > > >>> One thing I find odd is that Builders were annotated with > > >>> @PluginBuilderFactory and are now annotated with @PluginFactory. > > >>> Previously, only factory methods were annotated with @PluginFactory. > > >>> What > > >>> is odd is that the methods previously annotated with > > >>> @PluginBuilderFactory > > >>> create a Builder. They builder then creates the plugin object. However > > >>> the > > >>> methods annotated with @PluginFactory directly created the plugin > > >>> object. > > >>> Now you have both annotated with @PluginFactory, which means some > > >>> methods > > >>> behave one way and others behave another way. How is that clearer? > > >>> > > >>> That said changing both to @Inject has some merit although I am not sure > > >>> how you are determining that one is creating a Builder that then creates > > >>> the object vs a method that creates the object. > > >>> > > >>> But again, what problem is this trying to solve? How will this make > > >>> things > > >>> easier for users? > > >>> > > >>> Ralph > > >>> > > >>> > > >>> > > >>> > > >>>> On Oct 9, 2019, at 10:42 AM, Matt Sicker <boa...@gmail.com> wrote: > > >>>> > > >>>> To clarify on the mapping between javax.inject and the existing > > >>>> annotations, I believe this would work: > > >>>> > > >>>> @PluginFactory can be replaced by @Inject > > >>>> @PluginElement is a @Scope annotation > > >>>> @PluginAttribute is a @Qualifier annotation > > >>>> @PluginConfiguration could be a scope or singleton, but it's redundant > > >>>> @PluginNode could be a scope, but it's somewhat redundant > > >>>> @PluginValue would be a @Qualifier > > >>>> > > >>>> On Wed, 9 Oct 2019 at 10:05, Matt Sicker <boa...@gmail.com> wrote: > > >>>>> > > >>>>> Ok, I see the issue. I won’t add a dependency on the API. I do want to > > >>> try refactoring the 3.x API to use an annotation model similar to that. > > >>> I’ll show a proof of concept sometime soon. > > >>>>> > > >>>>> On Tue, Oct 8, 2019 at 18:50, Ralph Goers <ralph.go...@dslextreme.com> > > >>> wrote: > > >>>>>> > > >>>>>> I don’t understand. You can’t add javax.inject stuff into our > > >>> namespace without changing the package name. And if you change the > > >>> package > > >>> name I don’t see any benefit at all as the current names are much > > >>> clearer. > > >>>>>> > > >>>>>> I have no problem with Configurations being a plugin except it will > > >>> currently cause an endless loop as plugins are captured during > > >>> configuration. So any change you make here is going to be huge. > > >>>>>> > > >>>>>> Ralph > > >>>>>> > > >>>>>>> On Oct 8, 2019, at 2:23 PM, Matt Sicker <boa...@gmail.com> wrote: > > >>>>>>> > > >>>>>>> I'm thinking that the old annotations can be supported in terms of > > >>>>>>> the > > >>>>>>> javax.inject API. As for requiring a jar, that's why I've also > > >>>>>>> suggested just adopting the annotations into our own package > > >>>>>>> somewhere. > > >>>>>>> > > >>>>>>> Either way this is done, my general goal is to untangle other areas > > >>>>>>> in > > >>>>>>> the core API that could benefit from generic DI support. See for > > >>>>>>> example turning Configuration into a plugin. > > >>>>>>> > > >>>>>>> On Tue, 8 Oct 2019 at 15:40, Ralph Goers > > >>>>>>> <ralph.go...@dslextreme.com> > > >>> wrote: > > >>>>>>>> > > >>>>>>>> I don’t see how that relates. The proposal as I understand it is to > > >>> replace the existing annotations with annotations from javax.inject, > > >>> which > > >>> would require a JEE jar. > > >>>>>>>> > > >>>>>>>> Ralph > > >>>>>>>> > > >>>>>>>>> On Oct 8, 2019, at 1:31 PM, Jochen Wiedmann < > > >>> jochen.wiedm...@gmail.com> wrote: > > >>>>>>>>> > > >>>>>>>>> On Tue, Oct 8, 2019 at 10:26 PM Ralph Goers < > > >>> ralph.go...@dslextreme.com> wrote: > > >>>>>>>>>> > > >>>>>>>>>> IIUC this will require a dependency on a Java EE jar? For that > > >>> reason alone, no. > > >>>>>>>>> > > >>>>>>>>> Don't think so. A simple (mostly JSR 330 compliant) provider can > > >>>>>>>>> be > > >>>>>>>>> implemented in a few classes: > > >>>>>>>>> > > >>>>>>>>> > > >>> https://github.com/jochenw/afw/tree/master/afw-core/src/main/java/com/github/jochenw/afw/core/inject/simple > > >>>>>>>>> > > >>>>>>>> > > >>>>>>>> > > >>>>>>> > > >>>>>>> > > >>>>>>> -- > > >>>>>>> Matt Sicker <boa...@gmail.com> > > >>>>>>> > > >>>>>> > > >>>>>> > > >>>>> -- > > >>>>> Matt Sicker <boa...@gmail.com> > > >>>> > > >>>> > > >>>> > > >>>> -- > > >>>> Matt Sicker <boa...@gmail.com> > > >>>> > > >>> > > >>> > > >>> -- > > >> Matt Sicker <boa...@gmail.com> > > > > > > > > > > > > > > > > -- > Matt Sicker <boa...@gmail.com> -- Matt Sicker <boa...@gmail.com>