Skip to content

Commit

Permalink
feat: add more static entry methods in Wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
oldratlee committed Mar 21, 2024
1 parent 5f46ce8 commit 4253424
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 3 deletions.
51 changes: 51 additions & 0 deletions src/main/java/io/foldright/inspectablewrappers/Wrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import edu.umd.cs.findbugs.annotations.ReturnValuesAreNonnullByDefault;

import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

import static io.foldright.inspectablewrappers.InternalUtils.unwrapNonNull;
Expand Down Expand Up @@ -46,6 +49,24 @@ static <W> boolean isInstanceOf(W wrapper, Class<?> clazz) {
return inspect(wrapper, w -> clazz.isAssignableFrom(w.getClass()));
}

/**
* Returns the underlying instance of the wrapper chain.
* <p>
* The wrapper chain consists of wrapper itself, followed by the wrappers
* obtained by repeatedly calling {@link #unwrap()}.
*
* @param wrapper wrapper instance/wrapper chain
* @param <W> the type of instances that be wrapped
* @return the underlying instance that be wrapped
*/
@SuppressWarnings("unchecked")
static <W> W unwrapChain(W wrapper) {
requireNonNull(wrapper, "wrapper is null");
Object w = wrapper;
while (w instanceof Wrapper) w = unwrapNonNull(w);
return (W) w;
}

/**
* Reports whether any wrapper on the wrapper chain satisfy the given {@code predicate}.
* <p>
Expand All @@ -69,6 +90,36 @@ static <W> boolean inspect(final W wrapper, final Predicate<? super W> predicate
return false;
}

static <W> List<W> chainInstanceList(final W wrapper) {
List<W> ret = new ArrayList<>();
forEach(wrapper, ret::add);
return ret;
}

/**
* Performs the given action for each wrapper on the wrapper chain until all elements have been processed
* or the action throws an exception. Actions are performed in the order of wrapper chain.
* Exceptions thrown by the action are relayed to the caller.
* <p>
* The wrapper chain consists of wrapper itself, followed by the wrappers
* obtained by repeatedly calling {@link #unwrap()}.
*
* @param wrapper wrapper instance/wrapper chain
* @param action The action to be performed for wrapper on the wrapper chain
* @param <W> the type of instances that be wrapped
*/
@SuppressWarnings("unchecked")
static <W> void forEach(final W wrapper, final Consumer<? super W> action) {
requireNonNull(wrapper, "wrapper is null");
requireNonNull(action, "action is null");
Object w = wrapper;
while (w instanceof Wrapper) {
action.accept((W) w);
w = unwrapNonNull(w);
}
action.accept((W) w);
}

/**
* Retrieves the attachment of wrapper of given key on the wrapper chain
* by calling {@link Attachable#getAttachment(Object)}.
Expand Down
20 changes: 17 additions & 3 deletions src/test/java/io/foldright/inspectablewrappers/WrapperTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,40 @@ import io.foldright.inspectablewrappers.utils.AttachableDelegate
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.booleans.shouldBeFalse
import io.kotest.matchers.booleans.shouldBeTrue
import io.kotest.matchers.collections.shouldContainExactly
import io.kotest.matchers.nulls.shouldBeNull
import io.kotest.matchers.shouldBe
import io.kotest.matchers.types.shouldBeSameInstanceAs
import java.util.concurrent.Executor
import java.util.concurrent.ExecutorService

class WrapperTest : FunSpec({
// prepare executor instance and wrappers
val chatty: Executor = Executor { runnable -> runnable.run() }.let {
LazyExecutorWrapper(it).apply { setAttachment("busy", "very, very busy!") }
}.let(::ChattyExecutorWrapper)
val executor = Executor { runnable -> runnable.run() }

val lazy = LazyExecutorWrapper(executor).apply { setAttachment("busy", "very, very busy!") }

val chatty: Executor = lazy.let(::ChattyExecutorWrapper)

test("wrapper") {
Wrapper.isInstanceOf(chatty, LazyExecutorWrapper::class.java).shouldBeTrue()
Wrapper.isInstanceOf(chatty, ExecutorService::class.java).shouldBeFalse()

val value: String = Wrapper.getAttachment(chatty, "busy")!!
value shouldBe "very, very busy!"
}

test("unwrapChain") {
Wrapper.unwrapChain(chatty) shouldBeSameInstanceAs executor
}

test("getAttachment") {
Wrapper.getAttachment<Executor, String, String>(chatty, "not existed").shouldBeNull()
}

test("forEach") {
Wrapper.chainInstanceList(chatty).shouldContainExactly(chatty, lazy, executor)
}
})

class ChattyExecutorWrapper(private val executor: Executor) : Executor, Wrapper<Executor> {
Expand Down

0 comments on commit 4253424

Please sign in to comment.