You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2020/06/27 18:04:20 UTC

[commons-text] branch master updated: Add BiStringLookup and implementation BiFunctionStringLookup.

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-text.git


The following commit(s) were added to refs/heads/master by this push:
     new 54abd28  Add BiStringLookup and implementation BiFunctionStringLookup.
54abd28 is described below

commit 54abd281c8e95637b8a57a75859ddfd77ceff302
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sat Jun 27 14:04:13 2020 -0400

    Add BiStringLookup and implementation BiFunctionStringLookup.
---
 src/changes/changes.xml                            |  7 +-
 .../commons/text/lookup/AbstractStringLookup.java  | 20 ++---
 ...ringLookup.java => BiFunctionStringLookup.java} | 57 +++++++------
 .../{StringLookup.java => BiStringLookup.java}     | 19 +++--
 .../commons/text/lookup/FunctionStringLookup.java  | 27 +++---
 .../apache/commons/text/lookup/StringLookup.java   |  5 +-
 .../commons/text/lookup/StringLookupFactory.java   | 19 ++++-
 .../text/lookup/BiFunctionStringLookupTest.java    | 98 ++++++++++++++++++++++
 .../text/lookup/FunctionStringLookupTest.java      |  2 +
 9 files changed, 180 insertions(+), 74 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index d43e07a..bf5a2d5 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -53,9 +53,10 @@ The <action> type attribute can be add,update,fix,remove.
     <action                  type="add" dev="ggregory" due-to="Gary Gregory">Add StringMatcher.size().</action>
     <action                  type="add" dev="ggregory" due-to="Gary Gregory">Refactor TextStringBuilder.readFrom(Readable), extracting readFrom(CharBuffer) and readFrom(Reader).</action>    
     <action issue="TEXT-177" type="update" dev="ggregory" due-to="Gary Gregory">Update from Apache Commons Lang 3.9 to 3.10.</action>
-    <action                  type="add" dev="ggregory">Add org.apache.commons.text.matcher.StringMatcher.isMatch(CharSequence, int).</action>
-    <action                  type="add" dev="ggregory">Add org.apache.commons.text.matcher.StringMatcher.isMatch(CharSequence, int, int, int).</action>
-    <action                  type="add" dev="ggregory">Add org.apache.commons.text.lookup.StringLookupFactory.functionStringLookup(Function&lt;String, V&gt;).</action>
+    <action                  type="add" dev="ggregory" due-to="Gary Gregory">Add org.apache.commons.text.matcher.StringMatcher.isMatch(CharSequence, int).</action>
+    <action                  type="add" dev="ggregory" due-to="Gary Gregory">Add org.apache.commons.text.matcher.StringMatcher.isMatch(CharSequence, int, int, int).</action>
+    <action                  type="add" dev="ggregory" due-to="Gary Gregory">Add org.apache.commons.text.lookup.StringLookupFactory.functionStringLookup(Function&lt;String, V&gt;).</action>
+    <action                  type="add" dev="ggregory" due-to="Gary Gregory">Add BiStringLookup and implementation BiFunctionStringLookup.</action>
     <action                  type="update" dev="ggregory" due-to="Gary Gregory">[test] junit-jupiter 5.5.1 -> 5.5.2.</action>
     <action                  type="update" dev="ggregory" due-to="Gary Gregory">[test] org.assertj:assertj-core 3.13.2 -> 3.16.1.</action>
     <action                  type="update" dev="ggregory" due-to="Gary Gregory">[build] com.puppycrawl.tools:checkstyle 8.23 -> 8.27.</action>
diff --git a/src/main/java/org/apache/commons/text/lookup/AbstractStringLookup.java b/src/main/java/org/apache/commons/text/lookup/AbstractStringLookup.java
index 0819ce6..00e80f2 100644
--- a/src/main/java/org/apache/commons/text/lookup/AbstractStringLookup.java
+++ b/src/main/java/org/apache/commons/text/lookup/AbstractStringLookup.java
@@ -26,7 +26,6 @@ import org.apache.commons.lang3.StringUtils;
  */
 abstract class AbstractStringLookup implements StringLookup {
 
-
     /**
      * The empty string.
      */
@@ -45,10 +44,8 @@ abstract class AbstractStringLookup implements StringLookup {
     /**
      * Returns the substring after the first occurrence of {@code ch} in {@code value}.
      *
-     * @param value
-     *            The source string.
-     * @param ch
-     *            The character to search.
+     * @param value The source string.
+     * @param ch The character to search.
      * @return a new string.
      */
     protected String substringAfter(final String value, final char ch) {
@@ -59,10 +56,8 @@ abstract class AbstractStringLookup implements StringLookup {
     /**
      * Returns the substring after the first occurrence of {@code ch} in {@code value}.
      *
-     * @param value
-     *            The source string.
-     * @param ch
-     *            The character to search.
+     * @param value The source string.
+     * @param ch The character to search.
      * @return a new string.
      */
     protected String substringAfterLast(final String value, final char ch) {
@@ -73,13 +68,12 @@ abstract class AbstractStringLookup implements StringLookup {
     /**
      * Returns the substring after the first occurrence of {@code str} in {@code value}.
      *
-     * @param value
-     *            The source string.
-     * @param str
-     *            The string to search.
+     * @param value The source string.
+     * @param str The string to search.
      * @return a new string.
      */
     protected String substringAfter(final String value, final String str) {
         return StringUtils.substringAfter(value, str);
     }
+
 }
diff --git a/src/main/java/org/apache/commons/text/lookup/FunctionStringLookup.java b/src/main/java/org/apache/commons/text/lookup/BiFunctionStringLookup.java
similarity index 64%
copy from src/main/java/org/apache/commons/text/lookup/FunctionStringLookup.java
copy to src/main/java/org/apache/commons/text/lookup/BiFunctionStringLookup.java
index d262337..e62e601 100644
--- a/src/main/java/org/apache/commons/text/lookup/FunctionStringLookup.java
+++ b/src/main/java/org/apache/commons/text/lookup/BiFunctionStringLookup.java
@@ -18,58 +18,52 @@ package org.apache.commons.text.lookup;
 
 import java.util.Map;
 import java.util.Objects;
-import java.util.function.Function;
+import java.util.function.BiFunction;
 
 /**
  * A function-based lookup where the request for a lookup is answered by applying that function with a key.
  *
- * @param <V>
- *            A function's input type
+ * @param <R> A function's return type
+ * @param <P> A function's second input type
  *
  * @since 1.9
  */
-final class FunctionStringLookup<V> implements StringLookup {
+final class BiFunctionStringLookup<P, R> implements BiStringLookup<P> {
 
     /**
      * Creates a new instance backed by a Function.
      *
-     * @param <T>
-     *            the function's input type
-     * @param function
-     *            the function, may be null.
+     * @param <T> the function's input type
+     * @param biFunction the function, may be null.
      * @return a new instance backed by the given function.
      */
-    static <T> FunctionStringLookup<T> on(final Function<String, T> function) {
-        return new FunctionStringLookup<>(function);
+    static <U, T> BiFunctionStringLookup<U, T> on(final BiFunction<String, U, T> biFunction) {
+        return new BiFunctionStringLookup<>(biFunction);
     }
 
     /**
      * Creates a new instance backed by a Map. Used by the default lookup.
      *
-     * @param <T>
-     *            the map's value type.
-     * @param map
-     *            the map of keys to values, may be null.
+     * @param <T> the map's value type.
+     * @param map the map of keys to values, may be null.
      * @return a new instance backed by the given map.
      */
-    static <T> FunctionStringLookup<T> on(final Map<String, T> map) {
-        return on(key -> map.get(key));
+    static <U, T> BiFunctionStringLookup<U, T> on(final Map<String, T> map) {
+        return on((key, u) -> map.get(key));
     }
 
-
     /**
      * Function.
      */
-    private final Function<String, V> function;
+    private final BiFunction<String, P, R> biFunction;
 
     /**
      * Creates a new instance backed by a Function.
      *
-     * @param function
-     *            the function, may be null.
+     * @param biFunction the function, may be null.
      */
-    private FunctionStringLookup(final Function<String, V> function) {
-        this.function = function;
+    private BiFunctionStringLookup(final BiFunction<String, P, R> biFunction) {
+        this.biFunction = biFunction;
     }
 
     /**
@@ -77,8 +71,8 @@ final class FunctionStringLookup<V> implements StringLookup {
      *
      * @return The function used in lookups.
      */
-    Function<String, V> getFunction() {
-        return function;
+    BiFunction<String, P, R> getBiFunction() {
+        return biFunction;
     }
 
     /**
@@ -92,13 +86,13 @@ final class FunctionStringLookup<V> implements StringLookup {
      * @return The function result as a string, may be null.
      */
     @Override
-    public String lookup(final String key) {
-        if (function == null) {
+    public String lookup(final String key, final P object) {
+        if (biFunction == null) {
             return null;
         }
-        final V obj;
+        final R obj;
         try {
-            obj = function.apply(key);
+            obj = biFunction.apply(key, object);
         } catch (final SecurityException | NullPointerException | IllegalArgumentException e) {
             // Squelched. All lookup(String) will return null.
             // Could be a ConcurrentHashMap and a null key request
@@ -109,7 +103,12 @@ final class FunctionStringLookup<V> implements StringLookup {
 
     @Override
     public String toString() {
-        return super.toString() + " [map=" + function + "]";
+        return super.toString() + " [function=" + biFunction + "]";
+    }
+
+    @Override
+    public String lookup(String key) {
+        return lookup(key, null);
     }
 
 }
diff --git a/src/main/java/org/apache/commons/text/lookup/StringLookup.java b/src/main/java/org/apache/commons/text/lookup/BiStringLookup.java
similarity index 82%
copy from src/main/java/org/apache/commons/text/lookup/StringLookup.java
copy to src/main/java/org/apache/commons/text/lookup/BiStringLookup.java
index d89fdf2..90a3437 100644
--- a/src/main/java/org/apache/commons/text/lookup/StringLookup.java
+++ b/src/main/java/org/apache/commons/text/lookup/BiStringLookup.java
@@ -27,11 +27,13 @@ package org.apache.commons.text.lookup;
  * For example, it would be possible to implement a lookup that used the key as a primary key, and looked up the value
  * on demand from the database.
  * </p>
+ * 
+ * @param <U> The second argument type.
  *
- * @since 1.3
+ * @since 1.9
  */
 @FunctionalInterface
-public interface StringLookup {
+public interface BiStringLookup<U> extends StringLookup {
 
     /**
      * Looks up a String key to a String value.
@@ -52,12 +54,15 @@ public interface StringLookup {
      * <pre>
      * Map&lt;String, Object&gt; map = new HashMap&lt;String, Object&gt;();
      * map.put("number", new Integer(2));
-     * assertEquals("2", StringLookupFactory.mapStringLookup(map).lookup("number"));
+     * assertEquals("2", StringLookupFactory.biFunctionStringLookup(map).lookup("number", "A context object"));
      * </pre>
      *
-     * @param key
-     *            the key to look up, may be null
-     * @return The matching value, null if no match
+     * @param key the key to look up, may be null.
+     * @param object ignored by default.
+     * @return The matching value, null if no match.
      */
-    String lookup(String key);
+    default String lookup(final String key, final U object) {
+        return lookup(key);
+    }
+
 }
diff --git a/src/main/java/org/apache/commons/text/lookup/FunctionStringLookup.java b/src/main/java/org/apache/commons/text/lookup/FunctionStringLookup.java
index d262337..5fb234c 100644
--- a/src/main/java/org/apache/commons/text/lookup/FunctionStringLookup.java
+++ b/src/main/java/org/apache/commons/text/lookup/FunctionStringLookup.java
@@ -23,40 +23,34 @@ import java.util.function.Function;
 /**
  * A function-based lookup where the request for a lookup is answered by applying that function with a key.
  *
- * @param <V>
- *            A function's input type
+ * @param <V> A function's input type
  *
  * @since 1.9
  */
-final class FunctionStringLookup<V> implements StringLookup {
+final class FunctionStringLookup<V> extends AbstractStringLookup {
 
     /**
      * Creates a new instance backed by a Function.
      *
-     * @param <T>
-     *            the function's input type
-     * @param function
-     *            the function, may be null.
+     * @param <R> the function's input type
+     * @param function the function, may be null.
      * @return a new instance backed by the given function.
      */
-    static <T> FunctionStringLookup<T> on(final Function<String, T> function) {
+    static <R> FunctionStringLookup<R> on(final Function<String, R> function) {
         return new FunctionStringLookup<>(function);
     }
 
     /**
      * Creates a new instance backed by a Map. Used by the default lookup.
      *
-     * @param <T>
-     *            the map's value type.
-     * @param map
-     *            the map of keys to values, may be null.
+     * @param <V> the map's value type.
+     * @param map the map of keys to values, may be null.
      * @return a new instance backed by the given map.
      */
-    static <T> FunctionStringLookup<T> on(final Map<String, T> map) {
+    static <V> FunctionStringLookup<V> on(final Map<String, V> map) {
         return on(key -> map.get(key));
     }
 
-
     /**
      * Function.
      */
@@ -65,8 +59,7 @@ final class FunctionStringLookup<V> implements StringLookup {
     /**
      * Creates a new instance backed by a Function.
      *
-     * @param function
-     *            the function, may be null.
+     * @param function the function, may be null.
      */
     private FunctionStringLookup(final Function<String, V> function) {
         this.function = function;
@@ -109,7 +102,7 @@ final class FunctionStringLookup<V> implements StringLookup {
 
     @Override
     public String toString() {
-        return super.toString() + " [map=" + function + "]";
+        return super.toString() + " [function=" + function + "]";
     }
 
 }
diff --git a/src/main/java/org/apache/commons/text/lookup/StringLookup.java b/src/main/java/org/apache/commons/text/lookup/StringLookup.java
index d89fdf2..9b5e998 100644
--- a/src/main/java/org/apache/commons/text/lookup/StringLookup.java
+++ b/src/main/java/org/apache/commons/text/lookup/StringLookup.java
@@ -55,9 +55,8 @@ public interface StringLookup {
      * assertEquals("2", StringLookupFactory.mapStringLookup(map).lookup("number"));
      * </pre>
      *
-     * @param key
-     *            the key to look up, may be null
-     * @return The matching value, null if no match
+     * @param key the key to look up, may be null.
+     * @return The matching value, null if no match.
      */
     String lookup(String key);
 }
diff --git a/src/main/java/org/apache/commons/text/lookup/StringLookupFactory.java b/src/main/java/org/apache/commons/text/lookup/StringLookupFactory.java
index e0870da..05fc77b 100644
--- a/src/main/java/org/apache/commons/text/lookup/StringLookupFactory.java
+++ b/src/main/java/org/apache/commons/text/lookup/StringLookupFactory.java
@@ -20,6 +20,7 @@ package org.apache.commons.text.lookup;
 import java.nio.charset.StandardCharsets;
 import java.util.Base64;
 import java.util.Map;
+import java.util.function.BiFunction;
 import java.util.function.Function;
 
 import org.apache.commons.text.StringSubstitutor;
@@ -468,6 +469,20 @@ public final class StringLookupFactory {
     }
 
     /**
+     * Returns a new function-based lookup where the request for a lookup is answered by applying the function with a
+     * lookup key.
+     *
+     * @param <R> the function return type.
+     * @param <U> the funtion's second paremeter type.
+     * @param biFunction the function.
+     * @return a new MapStringLookup.
+     * @since 1.9
+     */
+    public <R, U> BiStringLookup<U> biFunctionStringLookup(final BiFunction<String, U, R> biFunction) {
+        return BiFunctionStringLookup.on(biFunction);
+    }
+
+    /**
      * Returns the ConstantStringLookup singleton instance to look up the value of a fully-qualified static final value.
      * <p>
      * Sometimes it is necessary in a configuration file to refer to a constant defined in a class. This can be done
@@ -624,12 +639,12 @@ public final class StringLookupFactory {
      * Returns a new function-based lookup where the request for a lookup is answered by applying the function with a
      * lookup key.
      *
-     * @param <V> the function input type.
+     * @param <R> the function return type.
      * @param function the function.
      * @return a new MapStringLookup.
      * @since 1.9
      */
-    public <V> StringLookup functionStringLookup(final Function<String, V> function) {
+    public <R> StringLookup functionStringLookup(final Function<String, R> function) {
         return FunctionStringLookup.on(function);
     }
 
diff --git a/src/test/java/org/apache/commons/text/lookup/BiFunctionStringLookupTest.java b/src/test/java/org/apache/commons/text/lookup/BiFunctionStringLookupTest.java
new file mode 100644
index 0000000..bb16ae8
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/lookup/BiFunctionStringLookupTest.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.commons.text.lookup;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiFunction;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link FunctionStringLookup}.
+ */
+public class BiFunctionStringLookupTest {
+
+    @Test
+    public void testConcurrentHashMapNull() {
+        Assertions.assertNull(BiFunctionStringLookup.on(new ConcurrentHashMap<>()).lookup(null));
+    }
+
+    @Test
+    public void testHashMapNull() {
+        Assertions.assertNull(BiFunctionStringLookup.on(new HashMap<>()).lookup(null));
+    }
+
+    @Test
+    public void testOne() {
+        final String key = "key";
+        final String value = "value";
+        final Map<String, String> map = new HashMap<>();
+        map.put(key, value);
+        Assertions.assertEquals(value, FunctionStringLookup.on(map).lookup(key));
+    }
+
+    private static final String SEPARATOR = ".";
+
+    @SuppressWarnings("unchecked")
+    private final BiFunction<String, Map<String, Object>, Object> nestedMapBiFunction = (k, m) -> {
+        final String keyCandidate = StringUtils.substringBefore(k, SEPARATOR);
+        if (keyCandidate.isEmpty()) {
+            return m.get(k);
+        }
+        Object value = m.get(keyCandidate);
+        if (value instanceof Map) {
+            return this.nestedMapBiFunction.apply(StringUtils.substringAfter(k, SEPARATOR),
+                (Map<String, Object>) value);
+        }
+        return value;
+    };
+
+    @Test
+    public void testBiFunctionForNestedMap() {
+        final String subSubKey = "subsubkeyMap";
+        final String subSubValue = "subsubvalue";
+        final Map<String, String> subSubMap = new HashMap<>();
+        subSubMap.put(subSubKey, subSubValue);
+        //
+        final String subKey = "subkey";
+        final String subKeyMap = "subkeyMap";
+        final String subValue = "subvalue";
+        final Map<String, Object> rootSubMap = new HashMap<>();
+        rootSubMap.put(subKey, subValue);
+        rootSubMap.put(subKeyMap, subSubMap);
+        //
+        final String rootKey = "keyMap";
+        final String rootKey2 = "key2";
+        final String rootValue2 = "value2";
+        final Map<String, Object> rootMap = new HashMap<>();
+        rootMap.put(rootKey, rootSubMap);
+        rootMap.put(rootKey2, rootValue2);
+        //
+        final BiStringLookup<Map<String, Object>> stringLookup = StringLookupFactory.INSTANCE
+            .biFunctionStringLookup(nestedMapBiFunction);
+        Assertions.assertEquals(rootValue2, stringLookup.lookup(rootKey2, rootMap));
+        Assertions.assertEquals(subValue, stringLookup.lookup(rootKey + SEPARATOR + subKey, rootMap));
+        Assertions.assertEquals(subSubValue,
+            stringLookup.lookup(rootKey + SEPARATOR + subKeyMap + SEPARATOR + subSubKey, rootMap));
+    }
+
+}
diff --git a/src/test/java/org/apache/commons/text/lookup/FunctionStringLookupTest.java b/src/test/java/org/apache/commons/text/lookup/FunctionStringLookupTest.java
index 1ae122e..af10943 100644
--- a/src/test/java/org/apache/commons/text/lookup/FunctionStringLookupTest.java
+++ b/src/test/java/org/apache/commons/text/lookup/FunctionStringLookupTest.java
@@ -20,7 +20,9 @@ package org.apache.commons.text.lookup;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiFunction;
 
+import org.apache.commons.lang3.StringUtils;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;