Skip to content

Instantly share code, notes, and snippets.

@hgschmie
Last active February 26, 2023 21:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hgschmie/2c46c37966351b4efe3764ecbbab1994 to your computer and use it in GitHub Desktop.
Save hgschmie/2c46c37966351b4efe3764ecbbab1994 to your computer and use it in GitHub Desktop.
Jdbi Extension Framework Rewrite

Extension Framework rewrite

The current extension framework is relatively simple. It supports attaching an extension interface which looks up a factory that then has the responsibility of either looking up an implementation class or create a proxy to execute code for each method.

Due to that simple structure, there are a number of inconsistencies, especially around the extension context and wrapping each method from an interface.

The main reason for this is that most of the interesting functionality for the extension code is not actually in the core/extension package but in sqlobject. Extension is little more than just a scaffold that was designed with sqlobject in mind.

There is nothing wrong with this. However, it is possible to move a lot of the "interesting" functionality from the sqlobject code into the core package without losing backwards compatibility and then making it possible to implement additional functionality using extensions.

How SQL Object works

SQL Objects uses three concepts:

  • Handlers. These are code pieces that are executed when an extension method is called. This is the code for SQLUpdate, SQLQuery etc.
  • HandlerDecorators. These code pieces change the behavior of a handler. Transactions are implemented as a decorator.
  • Configurers. These code pieces add or change the configuration for a method before it is called. This configuration is then spliced into the Handle through the ExtensionContext so that all code that runs within the Handler method uses that modified configuration. Configurers are used for the "Use..." annotations.

None of these concepts is SQLObject specific. This is generic code that can be used for any extension. But by being split out of the core and part of the sqlobject module, it is not available to any other extension or has to be copied and pasted.

Rewriting the extension framework

While the change looks big, it is mostly moving existing code around and cleaning it up. It introduces three new concepts to the core:

ExtensionHandler

ExtensionHandler - This is equivalent to the SqlObject Handler class.

ExtensionHandler.Factory - SqlObject HandlerFactory, but with the accepts / build pattern.

@UseExtensionHandler annotation - equivalent to @SqlOperation. It also provides an id attribute to allow multiple extensions to differentiate between @UseExtensionHandler instances intended for them or for another extension.

ExtensionHandlerCustomizer

ExtensionHandlerCustomizer - This is the equivalent of the SqlObject HandleDecorator

@UseExtensionCustomizer - This is the equivalent of the SqlObject @SqlMethodDecoratingAnnotation annotation.

@ExtensionCustomizationOrder - This is the equivalent of the SqlObject @DecoratorOrder annotation.

ExtensionConfigurer

ExtensionConfigurer - This is the equivalent of SqlObject Configurer. Literally.

ConfigCustomizer - This is an explicit interface where the SqlObject code uses Consumer<ConfigRegistry>. We are not consuming the registry, but customizing it. Makes code more readable.

ConfigCustomizerFactory - A factory class that creates a collection of ConfigCustomizer elements for an extension type or an extension type method. That concept existed sprawled out in the SqlObjectInitData class but was not pluggable and hardcoded to the Configurer interface.

@UseExtensionCustomizer - This is the equivalent of the SqlObject @ConfiguringAnnotation

Major changes to existing classes

ExtensionFactory gets a lot of new things, all of them with defaults that match the current code.

  • a set of flags to control extension factory behavior
  • bunch of getters for custom ExtensionHandlerFactories, ExtensionHandlerCustomizers and ExtensionConfigurerFactories

The Extensions configuration gets some new things:

  • methods to register ExtensionHandlerFactories, ExtensionHandlerCustomizers and ExtensionConfigurerFactories globally
  • a method to retrieve metadata for a given extension type

Major additions

ExtensionHandlerInvoker takes the role of InContextInvoker. All invokers are managed by the ExtensionMetadata class

ExtensionMetadata takes the role of SqlObjectInitData. It contains all of the discovered functionality from an extension type. It builds a map of ExtensionHandler objects that can be wrapped into an ExtensionInvoker with all customizers and configurers added. Those ExtensionInvoker classes are called through the Proxy when a method is invoked.

ExtensionFactoryDelegate wraps the functionality of the old SqlObjectFactory code. It may simply delegate to the actual factory generated object or create the map of ExtensionHandlers with corresponding ExtensionHandlerInvokers and wrap them into a proxy object.

Similar to the SqlObject code, a number of "glue" ExtensionHandlerFactory instances are used to create method handlers that are not managed by the extension specific code:

  • bridge methods
  • interface default methods
  • direct method invocations if the factory provides an actual object to attach to
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment