v1.0.1
The v1.0.1 release includes the following features and improvements:
- Asynchronous operations and limited support of aspects in DynamicClassExtension
- Some refactoring and cleanup to reduce code duplication
- Minor improvements and fixes
New Features in DynamicClassExtension
Asynchronous Operations
It is possible to use Builder.async() to declaratively define asynchronous operations. Such operations are running in background, and they are non-blocking therefore caller threads continue immediately.
DynamicClassExtension dynamicClassExtension = new DynamicClassExtension().builder(Item_Shippable.class).
opName("ship").
op(Book.class, shipBook(book)).async().
build();
Book book = new Book("The Mythical Man-Month");
dynamicClassExtension.extension(book, ItemShippable.class).ship();Notes:
- Operations must be already defined first via the
Builder.op()orBuilder.voidOp()methods - Non-void operations return
0ornullinstantly depending on the operation return type - Extension usage mirrors synchronous operations
- Ideal for long-running tasks to improve responsiveness
If there is a need to handle results of such asynchronous operations it can be done by specifying a lambda function as an argument for Builder.async().
DynamicClassExtension dynamicClassExtension = new DynamicClassExtension().builder(Item_Shippable.class).
opName("ship").
op(Book.class, shipBook(book)).
async((Book book, Throwable ex) -> System.out.println("Book shipped: " + book)).
build();
Book book = new Book("The Mythical Man-Month");
dynamicClassExtension.extension(book, ItemShippable.class).ship();Limited Support of AOP Aspects
The DynamicClassExtension provides limited support of Aspects by allowing to specify lambda functions which should be applied before and after performing of operations. It can be done via use of the Builder.before() and the Builder.after() methods.
DynamicClassExtension dynamicClassExtension = new DynamicClassExtension().builder(Item_Shippable.class).
opName("ship").
op(Book.class, shipBook(book)).
before((object, args) -> LOGGER.info("BEFORE: " + object + "-> ship()")).
after(result -> LOGGER.info("AFTER: result - " + result)).
build();
Book book = new Book("The Mythical Man-Month");
dynamicClassExtension.extension(book, ItemShippable.class).ship();Notes:
- Operations must be already defined first via
Builder.op()orBuilder.voidOp() - Both synchronous and asynchronous operations are supported
Aspects are only supported for defined operations only. So if there is a need to intercept calls of usual methods - such methods should be dynamically "overridden" by defining operations with the same signature. The following example intercepts Object.toString() method:
DynamicClassExtension dynamicClassExtension = new DynamicClassExtension().builder(Item_Shippable.class).
opName("toString").
op(Object.class, Object::toString).
before((object, args) -> LOGGER.info("BEFORE: " + object + "-> ship()")).
after(result -> LOGGER.info("AFTER: result - " + result)).
build();
Book book = new Book("The Mythical Man-Month");
dynamicClassExtension.extension(book, ItemShippable.class).toString();Altering Operations
To alter an operation itself:
- Remove it first using the
Builder.removeOp(...)method - Add a replacement operation using one of
Builder.op(...)orBuilder.voidOp(...)methods
DynamicClassExtension dynamicClassExtension = new DynamicClassExtension().builder(Item_Shippable.class).
opName("toString").
removeOp(Object.class,new Class<?>[0]).
op(Object.class, o -> "result: " + o.tostring()).
build();To alter properties of an operation:
- Make an alteration intention for the operation using the
Builder.alterOp(...)method - Specify properties for the operation e.g. by using the
Builder.async(...)method
DynamicClassExtension dynamicClassExtension = new DynamicClassExtension().builder(Item_Shippable.class).
opName("ship").
alterOp(Fuurniture.class,new Class<?>[0]).
async().
build();