Oh, almost forgot to mention my other main goal here: I have a hypothesis that if designed our APIs with inversion of control in mind, programmatic configuration and extension should be _much_ easier to support while maintaining backward compatibility, too. While the configuration framework itself is extremely powerful for creating fairly dynamic configurations, a non-trivial amount of users want more programmatic control than any of the APIs we support.
On Sat, 2 Nov 2019 at 16:04, Matt Sicker <boa...@gmail.com> wrote: > > 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> -- Matt Sicker <boa...@gmail.com>