From f18c4d080bfc30d547fe8bafc559655feb7c6472 Mon Sep 17 00:00:00 2001 From: Jerry Lee Date: Sat, 30 Mar 2024 23:57:12 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20add=20`IntegrationDemoUsingWrapperAdapt?= =?UTF-8?q?erUtils`=20=F0=9F=93=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 61 +++++++++++++++++- .../inspectablewrappers/WrapperAdapter.java | 4 +- .../utils/AttachableDelegate.java | 13 ++-- .../utils/WrapperAdapterUtils.java | 28 ++++++--- .../utils/package-info.java | 2 +- ...tegrationDemoUsingWrapperAdapterUtils.java | 62 +++++++++++++++++++ 6 files changed, 151 insertions(+), 19 deletions(-) create mode 100644 src/test/java/io/foldright/demo/integration/IntegrationDemoUsingWrapperAdapterUtils.java diff --git a/README.md b/README.md index 8f51a35..01ef08d 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ The purpose of **Inspectable Wrappers** is to provide a standard for wrapper cha - [🌰 Integration Demo](#-integration-demo) - [the demo existed wrapper cannot be modified](#the-demo-existed-wrapper-cannot-be-modified) - [the integration code](#the-integration-code) +- [🌰 Integration Demo using `WrapperAdapterUtils`](#-integration-demo-using-wrapperadapterutils) - [🍼 Java API Docs](#-java-api-docs) - [🍪 Dependency](#-dependency) @@ -50,7 +51,7 @@ The purpose of **Inspectable Wrappers** is to provide a standard for wrapper cha adapt an existed wrapper instance to type `Wrapper` without modifying it - The [`Inspector`](src/main/java/io/foldright/inspectablewrappers/Inspector.java) class is used to inspect the **wrapper chain** -- The util classes: +- The utility classes: - [`AttachableDelegate`](src/main/java/io/foldright/inspectablewrappers/utils/AttachableDelegate.java) class provides a simple `Attachable` delegate implementation - [`WrapperAdapterUtils`](src/main/java/io/foldright/inspectablewrappers/utils/WrapperAdapterUtils.java) class @@ -290,6 +291,64 @@ I'm working. > Runnable demo codes in project: [`IntegrationDemo.java`](src/test/java/io/foldright/demo/integration/IntegrationDemo.java) +## 🌰 Integration Demo using `WrapperAdapterUtils` + +Uses `WrapperAdapterUtils` to create `WrapperAdapter` instances without writing the boilerplate code to create a new adapter class. + +```java +public class IntegrationDemoUsingWrapperAdapterUtils { + public static void main(String[] args) { + final Executor executor = buildExecutorChain(); + + //////////////////////////////////////// + // inspect the executor(wrapper chain) + //////////////////////////////////////// + + System.out.println("Is executor ExistedExecutorWrapper? " + + containsInstanceOnWrapperChain(executor, ExistedExecutorWrapper.class)); + // print true + String adaptAttachment = getAttachmentFromWrapperChain(executor, "adapted-existed-executor-wrapper-msg"); + System.out.println("Adapted existed executor wrapper msg: " + adaptAttachment); + // print "I'm an adapter of an existed executor which have nothing to do with ~inspectable~wrappers~." + + //////////////////////////////////////// + // call executor(wrapper chain) + //////////////////////////////////////// + + System.out.println(); + executor.execute(() -> System.out.println("I'm working.")); + } + + private static Executor buildExecutorChain() { + final Executor base = Runnable::run; + final Executor adapter = createExistedExecutorWrapperAdapter(base); + return new ChattyExecutorWrapper(adapter); + } + + private static Executor createExistedExecutorWrapperAdapter(Executor base) { + final Executor existed = new ExistedExecutorWrapper(base); + + Attachable attachable = new AttachableDelegate<>(); + attachable.setAttachment("adapted-existed-executor-wrapper-msg", "I'm an adapter of an existed executor which have nothing to do with ~inspectable~wrappers~."); + + return WrapperAdapterUtils.createWrapperAdapter(Executor.class, base, existed, attachable); + } +} + +/* +demo output: + +Is executor ExistedExecutorWrapper? true +Adapted existed executor wrapper msg: I'm an adapter of an existed executor which have nothing to do with ~inspectable~wrappers~. + +BlaBlaBla... +I'm an adapter of an existed executor which have nothing to do with ~inspectable~wrappers~. +I'm working. + */ +``` + +> Runnable demo codes in project: [`IntegrationDemoUsingWrapperAdapterUtils.java`](src/test/java/io/foldright/demo/integration/IntegrationDemoUsingWrapperAdapterUtils.java) + ## 🍼 Java API Docs The current version Java API documentation: diff --git a/src/main/java/io/foldright/inspectablewrappers/WrapperAdapter.java b/src/main/java/io/foldright/inspectablewrappers/WrapperAdapter.java index 04cd36e..3760eaa 100644 --- a/src/main/java/io/foldright/inspectablewrappers/WrapperAdapter.java +++ b/src/main/java/io/foldright/inspectablewrappers/WrapperAdapter.java @@ -16,8 +16,8 @@ * width="400" alt="Wrapper Chain contains WrapperAdapter"> *

* Provided {@link io.foldright.inspectablewrappers.utils.WrapperAdapterUtils WrapperAdapterUtils} - * to create {@link WrapperAdapter} instances of the given biz interface type - * by the adaptee and underlying instance without writing boilerplate code of creating a new adapter class. + * to create {@link WrapperAdapter} instances of the given biz interface type by the underlying + * and adaptee instances without writing boilerplate codes of creating a new adapter class. * * @param the type of instances that be wrapped * @author Jerry Lee (oldratlee at gmail dot com) diff --git a/src/main/java/io/foldright/inspectablewrappers/utils/AttachableDelegate.java b/src/main/java/io/foldright/inspectablewrappers/utils/AttachableDelegate.java index 4455833..31599c8 100644 --- a/src/main/java/io/foldright/inspectablewrappers/utils/AttachableDelegate.java +++ b/src/main/java/io/foldright/inspectablewrappers/utils/AttachableDelegate.java @@ -1,9 +1,9 @@ package io.foldright.inspectablewrappers.utils; +import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import io.foldright.inspectablewrappers.Attachable; -import javax.annotation.ParametersAreNonnullByDefault; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -14,8 +14,8 @@ * A simple {@link Attachable} delegate implementation. *

* Note:
- * As the attachments are stored in {@code hash map}(threadsafe {@link ConcurrentHashMap}), the implementation of - * the key type must meet the requirements of the {@code hash map}, which means that + * As the attachments are stored in {@code hash map}(threadsafe {@link ConcurrentHashMap}), + * the implementation of the key type must meet the requirements of the {@code hash map}, which means that * a stable {@code hash code} and the ability to compare equality using {@code equals()} must be implemented. * * @author Jerry Lee (oldratlee at gmail dot com) @@ -23,7 +23,6 @@ * @author Zava Xu (zava dot kid at gmail dot com) * @see Attachable */ -@ParametersAreNonnullByDefault public class AttachableDelegate implements Attachable { private final ConcurrentMap attachments = new ConcurrentHashMap<>(); @@ -31,18 +30,18 @@ public class AttachableDelegate implements Attachable { * Sets an attachment. */ @Override - public void setAttachment(final K key, final V value) { + public void setAttachment(@NonNull K key, @NonNull V value) { requireNonNull(key, "key is null"); requireNonNull(value, "value is null"); attachments.put(key, value); } /** - * Gets the attachment of the given key. + * Gets the attachment value for the given key. */ @Nullable @Override - public V getAttachment(final K key) { + public V getAttachment(@NonNull K key) { requireNonNull(key, "key is null"); return attachments.get(key); } diff --git a/src/main/java/io/foldright/inspectablewrappers/utils/WrapperAdapterUtils.java b/src/main/java/io/foldright/inspectablewrappers/utils/WrapperAdapterUtils.java index c288788..9336a38 100644 --- a/src/main/java/io/foldright/inspectablewrappers/utils/WrapperAdapterUtils.java +++ b/src/main/java/io/foldright/inspectablewrappers/utils/WrapperAdapterUtils.java @@ -19,26 +19,32 @@ /** * Utility class for creating {@link WrapperAdapter} instances - * without writing the boilerplate code to create a new adapter class. + * without writing boilerplate codes of creating a new adapter class. * * @author Jerry Lee (oldratlee at gmail dot com) */ @ParametersAreNonnullByDefault public final class WrapperAdapterUtils { /** - * Creates a {@link WrapperAdapter} instance with the given biz interface type - * by the underlying instance that be wrapped and the adapted/existed wrapper instance. + * Creates a {@link WrapperAdapter} instance of the given biz interface type by + * the underlying({@link Wrapper#unwrap()}) and adaptee({@link WrapperAdapter#adaptee()}) instances. * * @param the type of instances that be wrapped * @param bizInterface the class of instances that be wrapped * @param underlying the underlying instance that be wrapped, more info see {@link Wrapper#unwrap()} * @param adaptee the adapted/existed wrapper instance, more info see {@link WrapperAdapter#adaptee()} * @return the new {@link WrapperAdapter} instance + * @throws IllegalArgumentException if {@code bizInterface} is not an interface, + * or {@code bizInterface} is {@link Wrapper}/{@link WrapperAdapter}/{@link Attachable}, + * or underlying is not an instance of {@code bizInterface}, + * or adaptee is not an instance of {@code bizInterface}, + * or adaptee is an instance of {@link Wrapper} + * @throws NullPointerException if any argument is null * @see Wrapper#unwrap() * @see WrapperAdapter#adaptee() */ @NonNull - public static T createWrapperAdapter(Class bizInterface, T underlying, T adaptee) { + public static T createWrapperAdapter(Class bizInterface, T underlying, T adaptee) { return createWrapperAdapter0( requireNonNull(bizInterface, "bizInterface is null"), requireNonNull(underlying, "underlying is null"), @@ -47,8 +53,8 @@ public static T createWrapperAdapter(Class bizInterface, T underlying, T } /** - * Creates a {@link WrapperAdapter} instance with the given biz interface type and {@link Attachable} type - * by the underlying instance that be wrapped, the adapted/existed wrapper instance and an attachable instance. + * Creates a {@link WrapperAdapter} instance of the given biz interface type and {@link Attachable} type by + * the underlying({@link Wrapper#unwrap()}), adaptee({@link WrapperAdapter#adaptee()}) and attachable instance. * * @param the type of instances that be wrapped * @param bizInterface the class of instances that be wrapped @@ -56,6 +62,12 @@ public static T createWrapperAdapter(Class bizInterface, T underlying, T * @param adaptee the adapted/existed wrapper instance, more info see {@link WrapperAdapter#adaptee()} * @param attachable the attachable instance, more info see {@link Attachable} * @return the new {@link WrapperAdapter} instance + * @throws IllegalArgumentException if {@code bizInterface} is not an interface, + * or {@code bizInterface} is {@link Wrapper}/{@link WrapperAdapter}/{@link Attachable}, + * or underlying is not an instance of {@code bizInterface}, + * or adaptee is not an instance of {@code bizInterface}, + * or adaptee is an instance of {@link Wrapper} + * @throws NullPointerException if any argument is null * @see Wrapper#unwrap() * @see WrapperAdapter#adaptee() * @see Attachable#getAttachment(Object) @@ -63,7 +75,7 @@ public static T createWrapperAdapter(Class bizInterface, T underlying, T */ @NonNull public static T createWrapperAdapter( - Class bizInterface, T underlying, T adaptee, Attachable attachable) { + Class bizInterface, T underlying, T adaptee, Attachable attachable) { return createWrapperAdapter0( requireNonNull(bizInterface, "bizInterface is null"), requireNonNull(underlying, "underlying is null"), @@ -73,7 +85,7 @@ public static T createWrapperAdapter( @SuppressWarnings({"unchecked", "rawtypes"}) private static T createWrapperAdapter0( - Class bizInterface, T underlying, T adaptee, @Nullable Attachable attachable) { + Class bizInterface, T underlying, T adaptee, @Nullable Attachable attachable) { checkTypeRequirements(bizInterface, underlying, adaptee); final InvocationHandler handler = (proxy, method, args) -> { diff --git a/src/main/java/io/foldright/inspectablewrappers/utils/package-info.java b/src/main/java/io/foldright/inspectablewrappers/utils/package-info.java index c00964d..4b0907b 100644 --- a/src/main/java/io/foldright/inspectablewrappers/utils/package-info.java +++ b/src/main/java/io/foldright/inspectablewrappers/utils/package-info.java @@ -1,5 +1,5 @@ /** - * Utils classes for {@code inspectable wrappers}. + * Utility classes for {@code inspectable wrappers}. * * @see io.foldright.inspectablewrappers.utils.AttachableDelegate * @see io.foldright.inspectablewrappers.utils.WrapperAdapterUtils diff --git a/src/test/java/io/foldright/demo/integration/IntegrationDemoUsingWrapperAdapterUtils.java b/src/test/java/io/foldright/demo/integration/IntegrationDemoUsingWrapperAdapterUtils.java new file mode 100644 index 0000000..9d0c227 --- /dev/null +++ b/src/test/java/io/foldright/demo/integration/IntegrationDemoUsingWrapperAdapterUtils.java @@ -0,0 +1,62 @@ +package io.foldright.demo.integration; + +import io.foldright.demo.ChattyExecutorWrapper; +import io.foldright.inspectablewrappers.Attachable; +import io.foldright.inspectablewrappers.utils.AttachableDelegate; +import io.foldright.inspectablewrappers.utils.WrapperAdapterUtils; + +import java.util.concurrent.Executor; + +import static io.foldright.inspectablewrappers.Inspector.containsInstanceOnWrapperChain; +import static io.foldright.inspectablewrappers.Inspector.getAttachmentFromWrapperChain; + + +public class IntegrationDemoUsingWrapperAdapterUtils { + public static void main(String[] args) { + final Executor executor = buildExecutorChain(); + + //////////////////////////////////////// + // inspect the executor(wrapper chain) + //////////////////////////////////////// + + System.out.println("Is executor ExistedExecutorWrapper? " + + containsInstanceOnWrapperChain(executor, ExistedExecutorWrapper.class)); + // print true + String adaptAttachment = getAttachmentFromWrapperChain(executor, "adapted-existed-executor-wrapper-msg"); + System.out.println("Adapted existed executor wrapper msg: " + adaptAttachment); + // print "I'm an adapter of an existed executor which have nothing to do with ~inspectable~wrappers~." + + //////////////////////////////////////// + // call executor(wrapper chain) + //////////////////////////////////////// + + System.out.println(); + executor.execute(() -> System.out.println("I'm working.")); + } + + private static Executor buildExecutorChain() { + final Executor base = Runnable::run; + final Executor adapter = createExistedExecutorWrapperAdapter(base); + return new ChattyExecutorWrapper(adapter); + } + + private static Executor createExistedExecutorWrapperAdapter(Executor base) { + final Executor existed = new ExistedExecutorWrapper(base); + + Attachable attachable = new AttachableDelegate<>(); + attachable.setAttachment("adapted-existed-executor-wrapper-msg", "I'm an adapter of an existed executor which have nothing to do with ~inspectable~wrappers~."); + + return WrapperAdapterUtils.createWrapperAdapter(Executor.class, base, existed, attachable); + } +} + +/* +demo output: + +Is executor ExistedExecutorWrapper? true +Adapted existed executor wrapper msg: I'm an adapter of an existed executor which have nothing to do with ~inspectable~wrappers~. + +BlaBlaBla... +I'm an adapter of an existed executor which have nothing to do with ~inspectable~wrappers~. +I'm working. + */