From 1899e08fed2622d750bb9b088bd1378177e9c435 Mon Sep 17 00:00:00 2001 From: Carlos Munoz Date: Mon, 13 Jul 2020 11:56:51 -0400 Subject: [PATCH] minor improvements to the ResourceTraversal api (#338) turned `ResourceTraversal` into a functional interface --- .../com/redhat/pantheon/model/api/Child.java | 2 +- .../model/api/util/ResourceTraversal.java | 71 ++++++++----------- .../model/api/util/ResourceTraversalTest.java | 22 ++++++ 3 files changed, 54 insertions(+), 41 deletions(-) diff --git a/pantheon-bundle/src/main/java/com/redhat/pantheon/model/api/Child.java b/pantheon-bundle/src/main/java/com/redhat/pantheon/model/api/Child.java index 8f8f8cfa1..82e776c1d 100644 --- a/pantheon-bundle/src/main/java/com/redhat/pantheon/model/api/Child.java +++ b/pantheon-bundle/src/main/java/com/redhat/pantheon/model/api/Child.java @@ -42,7 +42,7 @@ public interface Child extends Supplier { /** * Provides a null-safe way to operate on the value of the child, and return an * {@link Optional} with the result of the operation. This allowes the caller to - * continue to operapate in a null-safe fashion. + * continue to operate in a null-safe fashion. * @param func The function to apply to the value * @param * @return An optional indicating the result of the operation. If the operation diff --git a/pantheon-bundle/src/main/java/com/redhat/pantheon/model/api/util/ResourceTraversal.java b/pantheon-bundle/src/main/java/com/redhat/pantheon/model/api/util/ResourceTraversal.java index 06e1f0ad2..28aa05d52 100644 --- a/pantheon-bundle/src/main/java/com/redhat/pantheon/model/api/util/ResourceTraversal.java +++ b/pantheon-bundle/src/main/java/com/redhat/pantheon/model/api/util/ResourceTraversal.java @@ -25,15 +25,9 @@ * * @author Carlos Munoz */ -public class ResourceTraversal implements Supplier { +public interface ResourceTraversal extends Supplier { - private static final ResourceTraversal EMPTY = new ResourceTraversal<>(null); - - private final Optional currentResource; - - private ResourceTraversal(T resource) { - this.currentResource = ofNullable(resource); - } + ResourceTraversal EMPTY = (ResourceTraversal) () -> null; /** * Starts a resource tree traversal. @@ -42,8 +36,8 @@ private ResourceTraversal(T resource) { * @return A traversal object starting from the given {@link SlingModel}. If the model * is null, traversals will still conclude but will always yield null results. */ - public static final ResourceTraversal traverseFrom(@Nullable M model) { - return new ResourceTraversal<>(model); + static ResourceTraversal traverseFrom(@Nullable M model) { + return () -> model; } /** @@ -52,10 +46,13 @@ public static final ResourceTraversal traverseFrom(@Nu * @param * @return A resource traversal at the child accessed via the child accessor. */ - public ResourceTraversal toChild(Function> childAccessor) { - if(currentResource.isPresent()) { - Child nextTraversalChild = childAccessor.apply(currentResource.get()); - return new ResourceTraversal<>(nextTraversalChild.get()); + default ResourceTraversal toChild(Function> childAccessor) { + if(isPresent()) { + Child nextTraversalChild = childAccessor.apply(get()); + if(nextTraversalChild.isPresent()) { + return () -> nextTraversalChild.get(); + } + return (ResourceTraversal) EMPTY; } return (ResourceTraversal) EMPTY; } @@ -68,9 +65,9 @@ public ResourceTraversal toChild(Function Optional toField(Function> fieldAccessor) { - if(currentResource.isPresent()) { - Field field = fieldAccessor.apply(currentResource.get()); + default Optional toField(Function> fieldAccessor) { + if(isPresent()) { + Field field = fieldAccessor.apply(get()); return ofNullable(field.get()); } return Optional.empty(); @@ -84,41 +81,35 @@ public Optional toField(Function> fieldAccessor) { * @return A traversal object at the referenced object. * @see ResourceTraversal#toField(Function) for simple access to the reference value. */ - public ResourceTraversal toRef( + default ResourceTraversal toRef( Function> referenceAccessor) { - if(currentResource.isPresent()) { - Reference reference = referenceAccessor.apply(currentResource.get()); - try { - return new ResourceTraversal<>(reference.getReference()); - } - catch (RepositoryException e) { - // This happens when the reference is not found - // TODO Right now this just falls through and returns an empty traversal, - // but we might need to log an entry - } + if(isPresent()) { + Reference reference = referenceAccessor.apply(get()); + return () -> { + try { + return reference.getReference(); + } catch (RepositoryException e) { + // This happens when the reference is not found + // TODO Right now this just falls through and returns an empty traversal, + // but we might need to log an entry + return null; + } + }; } return (ResourceTraversal) EMPTY; } - /** - * @return The current resource in the traversal. May be null if the resource does not exist. - */ - @Override - public T get() { - return currentResource.orElse(null); - } - /** * @return The current resource in the traversal as an optional. */ - public Optional getAsOptional() { - return currentResource; + default Optional getAsOptional() { + return Optional.ofNullable(get()); } /** * @return True, if the current resource in the traversal exists, false otherwise. */ - public boolean isPresent() { - return currentResource.isPresent(); + default boolean isPresent() { + return get() != null; } } diff --git a/pantheon-bundle/src/test/java/com/redhat/pantheon/model/api/util/ResourceTraversalTest.java b/pantheon-bundle/src/test/java/com/redhat/pantheon/model/api/util/ResourceTraversalTest.java index d48331099..4a624c0cf 100644 --- a/pantheon-bundle/src/test/java/com/redhat/pantheon/model/api/util/ResourceTraversalTest.java +++ b/pantheon-bundle/src/test/java/com/redhat/pantheon/model/api/util/ResourceTraversalTest.java @@ -117,6 +117,28 @@ void incompleteReferenceTraversal() { .isPresent()); } + @Test + void getAsOptionalTest() { + // Given + sc.build() + .resource("/level1/level2") + .commit(); + ResourceTraversalTest.Level1 startModel = SlingModels.getModel(sc.resourceResolver().getResource("/level1"), ResourceTraversalTest.Level1.class); + + // When + + // Then + assertTrue(ResourceTraversal.traverseFrom(startModel) + .toChild(ResourceTraversalTest.Level1::level2) + .getAsOptional() + .isPresent()); + assertFalse(ResourceTraversal.traverseFrom(startModel) + .toChild(ResourceTraversalTest.Level1::level2) + .toChild(ResourceTraversalTest.Level2::level3) + .getAsOptional() + .isPresent()); + } + interface Level1 extends SlingModel { Child level2();