diff --git a/README.md b/README.md index 9a21e885..96938a3f 100644 --- a/README.md +++ b/README.md @@ -486,8 +486,45 @@ CacheProvider.setCache(new Cache() { }); ``` +### Custom Path Functions +If you want to implement you own path functions, create your PathFunction implementation. +Initializing PathFunctionFactory should only be done when your application is being initialized. +```java + +class MyPathFunction implements PathFunction { + + public static final String NAME = "mypathfunc"; + + @Override + public Object invoke( + String currentPath, + PathRef parent, + Object model, + EvaluationContext ctx, + List parameters + ) { + // Do something here + + return model; + } +} + +// Example application initialization +class ApplicationBoot { + public static void main(String[] args) { + + PathFunctionFactory.add( + MyPathFunction.NAME, + MyPathFunction.class + ); + + PathFunctionFactory.init(); + } +} + +``` diff --git a/json-path/src/main/java/com/jayway/jsonpath/PathFunctionFactory.java b/json-path/src/main/java/com/jayway/jsonpath/PathFunctionFactory.java new file mode 100644 index 00000000..569b3099 --- /dev/null +++ b/json-path/src/main/java/com/jayway/jsonpath/PathFunctionFactory.java @@ -0,0 +1,80 @@ +package com.jayway.jsonpath; + +import com.jayway.jsonpath.internal.function.PathFunction; + +import java.util.Collections; +import java.util.Map; + +public class PathFunctionFactory { + + private static boolean initialized = false; + + /** + * by default, we add th common path functions + */ + private static Map functions = com.jayway.jsonpath.internal.function.PathFunctionFactory.getFunctions(); + + /** + * Add a single custom path function + * Should only be done when your application is being initialized + * + * @param name The name of the function + * @param clazz Class of a function + * @throws InvalidPathException + */ + public static void add(String name, Class clazz) throws InvalidPathException { + assertNotInitialized(); + if (functions.containsKey(name)) { + throw new InvalidPathException("Path function with name: " + name + " already exists"); + } + + functions.put(name, clazz); + } + + /** + * Add a map custom path function + * Should only be done when your application is being initialized + * + * @param functionMap The name of the function as key, Class of a function as Value + * @throws InvalidPathException + */ + public static void add(Map functionMap) throws InvalidPathException { + for (Map.Entry entry : functionMap.entrySet()) { + add(entry.getKey(), entry.getValue()); + } + } + + /** + * Should only your application initialized to + */ + public static void init() { + if (initialized) { + return; + } + functions.putAll(com.jayway.jsonpath.internal.function.PathFunctionFactory.getFunctions()); + functions = Collections.unmodifiableMap(functions); + initialized = true; + } + + public static PathFunction newFunction(String name) throws InvalidPathException { + // Lazy init + init(); + + Class functionClazz = functions.get(name); + if (functionClazz == null) { + throw new InvalidPathException("Function with name: " + name + " does not exist."); + } else { + try { + return (PathFunction) functionClazz.newInstance(); + } catch (Exception e) { + throw new InvalidPathException("Function of name: " + name + " cannot be created", e); + } + } + } + + private static void assertNotInitialized() { + if (initialized) { + throw new InvalidPathException("Can not change path function factory after it is initialized"); + } + } +} diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/function/PathFunctionFactory.java b/json-path/src/main/java/com/jayway/jsonpath/internal/function/PathFunctionFactory.java index 3a31151f..eba97a5a 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/function/PathFunctionFactory.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/function/PathFunctionFactory.java @@ -32,6 +32,20 @@ public class PathFunctionFactory { static { // New functions should be added here and ensure the name is not overridden + Map map = getFunctions(); + + FUNCTIONS = Collections.unmodifiableMap(map); + } + + /** + * Returns the common/core functions. + * + * @see #FUNCTIONS + * @see PathFunction + * + * @return Map of path functions keyed by name + */ + public static Map getFunctions() { Map map = new HashMap(); // Math Functions @@ -55,11 +69,11 @@ public class PathFunctionFactory { map.put("last", Last.class); map.put("index", Index.class); - - FUNCTIONS = Collections.unmodifiableMap(map); + return map; } /** + * @deprecated * Returns the function by name or throws InvalidPathException if function not found. * * @see #FUNCTIONS diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/path/FunctionPathToken.java b/json-path/src/main/java/com/jayway/jsonpath/internal/path/FunctionPathToken.java index 0f449895..a2663318 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/path/FunctionPathToken.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/path/FunctionPathToken.java @@ -4,7 +4,7 @@ import com.jayway.jsonpath.internal.Path; import com.jayway.jsonpath.internal.PathRef; import com.jayway.jsonpath.internal.function.Parameter; import com.jayway.jsonpath.internal.function.PathFunction; -import com.jayway.jsonpath.internal.function.PathFunctionFactory; +import com.jayway.jsonpath.PathFunctionFactory; import com.jayway.jsonpath.internal.function.latebinding.JsonLateBindingValue; import com.jayway.jsonpath.internal.function.latebinding.PathLateBindingValue;