Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions json-path/src/main/java/com/jayway/jsonpath/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Map;
import java.util.Set;

import static com.jayway.jsonpath.internal.Utils.notNull;
Expand Down Expand Up @@ -55,8 +56,10 @@ private static Defaults getEffectiveDefaults(){
private final MappingProvider mappingProvider;
private final Set<Option> options;
private final Collection<EvaluationListener> evaluationListeners;
private final Map<String, Class> functionMap;

private Configuration(JsonProvider jsonProvider, MappingProvider mappingProvider, EnumSet<Option> options, Collection<EvaluationListener> evaluationListeners) {
private Configuration(JsonProvider jsonProvider, MappingProvider mappingProvider, EnumSet<Option> options,
Collection<EvaluationListener> evaluationListeners, Map<String, Class> functionMap) {
notNull(jsonProvider, "jsonProvider can not be null");
notNull(mappingProvider, "mappingProvider can not be null");
notNull(options, "setOptions can not be null");
Expand All @@ -65,6 +68,7 @@ private Configuration(JsonProvider jsonProvider, MappingProvider mappingProvider
this.mappingProvider = mappingProvider;
this.options = Collections.unmodifiableSet(options);
this.evaluationListeners = Collections.unmodifiableCollection(evaluationListeners);
this.functionMap = functionMap;
}

/**
Expand Down Expand Up @@ -127,6 +131,15 @@ public MappingProvider mappingProvider() {
return mappingProvider;
}

/**
* Returns {@link com.jayway.jsonpath.internal.function.PathFunction} defined in functionMap.
* @param name
* @return null if there are no functionMap defined or the function is not defined.
*/
public Map<String, Class> getFunctionMap() {
return functionMap;
}

/**
* Creates a new configuration by adding the new options to the options used in this configuration.
* @param options options to add
Expand Down Expand Up @@ -189,6 +202,8 @@ public static class ConfigurationBuilder {

private JsonProvider jsonProvider;
private MappingProvider mappingProvider;
private Map<String, Class> functionMap;

private EnumSet<Option> options = EnumSet.noneOf(Option.class);
private Collection<EvaluationListener> evaluationListener = new ArrayList<EvaluationListener>();

Expand All @@ -202,6 +217,11 @@ public ConfigurationBuilder mappingProvider(MappingProvider provider) {
return this;
}

public ConfigurationBuilder functionMap(Map<String, Class> functionMap) {
this.functionMap = functionMap;
return this;
}

public ConfigurationBuilder options(Option... flags) {
if(flags.length > 0) {
this.options.addAll(asList(flags));
Expand Down Expand Up @@ -234,7 +254,7 @@ public Configuration build() {
mappingProvider = defaults.mappingProvider();
}
}
return new Configuration(jsonProvider, mappingProvider, options, evaluationListener);
return new Configuration(jsonProvider, mappingProvider, options, evaluationListener, functionMap);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.jayway.jsonpath.internal.function;

import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.InvalidPathException;
import com.jayway.jsonpath.internal.function.json.Append;
import com.jayway.jsonpath.internal.function.numeric.Average;
Expand Down Expand Up @@ -64,8 +65,17 @@ public class PathFunctionFactory {
*
* @throws InvalidPathException
*/
public static PathFunction newFunction(String name) throws InvalidPathException {
Class functionClazz = FUNCTIONS.get(name);
public static PathFunction newFunction(String name, Configuration conf) throws InvalidPathException {
Class functionClazz = null;
if (conf != null && conf.getFunctionMap() != null) {
Map<String, Class> confFunctionMap = conf.getFunctionMap();
functionClazz = confFunctionMap.get(name);
}

if (functionClazz == null) {
functionClazz = FUNCTIONS.get(name);
}

if(functionClazz == null){
throw new InvalidPathException("Function with name: " + name + " does not exist.");
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public FunctionPathToken(String pathFragment, List<Parameter> parameters) {

@Override
public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
PathFunction pathFunction = PathFunctionFactory.newFunction(functionName);
PathFunction pathFunction = PathFunctionFactory.newFunction(functionName, ctx.configuration());
evaluateParameters(currentPath, parent, model, ctx);
Object result = pathFunction.invoke(currentPath, parent, model, ctx, functionParams);
ctx.addResult(currentPath + "." + functionName, parent, result);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.jayway.jsonpath.internal.function;

import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.Configurations;
import com.jayway.jsonpath.InvalidPathException;
import com.jayway.jsonpath.internal.EvaluationContext;
import com.jayway.jsonpath.internal.PathRef;
import com.jayway.jsonpath.internal.function.numeric.Max;
import com.jayway.jsonpath.spi.json.GsonJsonProvider;
import com.jayway.jsonpath.spi.mapper.GsonMappingProvider;
import org.junit.Test;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;

class ToLowerPathFunction implements PathFunction {
@Override
public Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List<Parameter> parameters) {
return ((String) model).toLowerCase();
}
}

public class FunctionDefinitionTest extends BaseFunctionTest {

@Test
public void testToLowerFunction() throws IllegalAccessException, InstantiationException {
Map<String, Class> funcMap = new HashMap<String, Class>();
funcMap.put("toLower", ToLowerPathFunction.class);
Configuration conf = Configuration
.builder()
.mappingProvider(new GsonMappingProvider())
.jsonProvider(new GsonJsonProvider())
.functionMap(funcMap)
.build();

verifyFunction(conf, "$.upper.toLower()", "{\"upper\":\"UPPERCASE\"}", "uppercase");
}

@Test
public void testUndefinedFunction() throws IllegalAccessException, InstantiationException {
Map<String, Class> funcMap = new HashMap<String, Class>();
funcMap.put("toLower", ToLowerPathFunction.class);
Configuration conf = Configuration
.builder()
.mappingProvider(new GsonMappingProvider())
.jsonProvider(new GsonJsonProvider())
.functionMap(funcMap)
.build();
boolean caughtException = false;
try {
verifyFunction(conf, "$.upper.undefined()", "{\"upper\":\"UPPERCASE\"}", "uppercase");
} catch (InvalidPathException exp) {
caughtException=true;
}
assertThat(caughtException);
}
}