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
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.jayway.jsonpath.internal.function.sequence.Index;
import com.jayway.jsonpath.internal.function.sequence.Last;
import com.jayway.jsonpath.internal.function.text.Concatenate;
import com.jayway.jsonpath.internal.function.text.Join;
import com.jayway.jsonpath.internal.function.text.Length;

import java.util.Collections;
Expand Down Expand Up @@ -43,6 +44,7 @@ public class PathFunctionFactory {

// Text Functions
map.put("concat", Concatenate.class);
map.put("join", Join.class);

// JSON Entity Functions
map.put(Length.TOKEN_NAME, Length.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package com.jayway.jsonpath.internal.function.text;

import com.jayway.jsonpath.internal.EvaluationContext;
import com.jayway.jsonpath.internal.PathRef;
import com.jayway.jsonpath.internal.function.ParamType;
import com.jayway.jsonpath.internal.function.Parameter;
import com.jayway.jsonpath.internal.function.PathFunction;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* join values in an array, supply two grammars:
* <p>
* 1. [].join([delimiter],[..path])
* 2. $.join([delimiter],[..path])
*/
public class Join implements PathFunction {
@Override
public Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List<Parameter> parameters) {
String delimiter = this.getDelimiterFromParameters(parameters);
Collection<String> results = Collections.emptyList();

// [].join([..path])
if (ctx.configuration().jsonProvider().isArray(model)) {
results = this.joinByArrayModel(model, ctx, parameters);
}

// $.join([delimiter],[..path])
if (null == results || results.size() == 0) {
results = this.joinByParams(ctx, parameters);
}

if (null == results || results.size() == 0) {
return "";
}
return String.join(delimiter, results);
}


/**
* get results by model
*
* @param model
* @param ctx
* @param parameters
* @return
*/
protected Collection<String> joinByArrayModel(Object model, EvaluationContext ctx, List<Parameter> parameters) {
Collection<String> resultList = new ArrayList<>();
List<Parameter> pathParams = Optional.ofNullable(parameters).orElseGet(Collections::emptyList)
.stream().filter(item -> ParamType.PATH.equals(item.getType())).collect(Collectors.toList());

if (pathParams.size() == 0) {
return this.arrayIterableToList(ctx, model, item -> null);
}

for (Parameter pathParam : pathParams) {
List<String> list = this.arrayIterableToList(ctx, model, item -> {
Object value = pathParam.getPath().evaluate(item, model, ctx.configuration()).getValue();
return this.arrayIterableToList(ctx, value, obj -> null);
});
if (null == list || list.size() == 0) {
continue;
}
resultList.addAll(list);
}
return resultList;
}


/**
* get results by params
*
* @param ctx
* @param parameters
* @return
*/
protected Collection<String> joinByParams(EvaluationContext ctx, List<Parameter> parameters) {
if (null == parameters || parameters.size() == 0) {
return null;
}
List<Parameter> notJsonParams = parameters.stream().filter(item -> ParamType.PATH.equals(item.getType())).collect(Collectors.toList());
if (notJsonParams.size() == 0) {
return parameters.stream().map(Parameter::getValue).filter(Objects::nonNull).map(Object::toString).collect(Collectors.toList());
}
List<String> list = Parameter.toList(String.class, ctx, notJsonParams);
return list.size() > 0 ? list : null;
}

/**
* get delimiter
*
* @param parameters
* @return
*/
protected String getDelimiterFromParameters(List<Parameter> parameters) {
if (null != parameters && parameters.size() >= 1) {
Parameter parameter = parameters.get(0);
if (ParamType.JSON.equals(parameter.getType())) {
return parameter.getValue().toString();
}
}
return ",";
}


/**
* literal quantity type
*
* @param obj
* @return
*/
protected boolean simpleType(Object obj) {
if (null == obj) {
return false;
}
return obj instanceof Number || obj instanceof CharSequence ||
obj instanceof Boolean || obj instanceof Character;
}


/**
* iterable
*
* @param ctx
* @param model
* @param itemIsNotSimpleFunc
*/
protected List<String> arrayIterableToList(EvaluationContext ctx, Object model, Function<Object, List<String>> itemIsNotSimpleFunc) {
if (null == model) {
return Collections.emptyList();
}

if (this.simpleType(model)) {
return Collections.singletonList(model.toString());
}

boolean isArray = ctx.configuration().jsonProvider().isArray(model);
if (!isArray) {
return Collections.emptyList();
}

List<String> resultList = new ArrayList<>();
Iterable<?> iterable = ctx.configuration().jsonProvider().toIterable(model);
for (Object obj : iterable) {
if (null == obj) {
continue;
}

boolean isSimpleType = this.simpleType(obj);
if (isSimpleType) {
resultList.add(obj.toString());
continue;
}

List<String> items = itemIsNotSimpleFunc.apply(obj);
if (null == items || items.size() == 0) {
continue;
}
resultList.addAll(items);
}
return resultList;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.Configurations;
import com.jayway.jsonpath.Option;
import net.minidev.json.JSONArray;
import org.junit.Test;

Expand Down Expand Up @@ -106,4 +107,16 @@ public void testPredicateWithFunctionCallTwoMatches() {
verifyFunction(conf, path, BATCH_JSON, values);
}



@Test
public void testParameterJoinFunctionCall() {
Configuration configuration = Configuration.builder().options(Option.DEFAULT_PATH_LEAF_TO_NULL, Option.SUPPRESS_EXCEPTIONS).build();
verifyFunction(configuration, "$.text.join()", TEXT_SERIES, "a,b,c,d,e,f");
verifyFunction(configuration, "$.text.join(\"|\")", TEXT_SERIES, "a|b|c|d|e|f");
verifyFunction(configuration, "$.join($.batches.results[*].productId)", BATCH_JSON, "23,23");
verifyFunction(configuration, "$.join(\" _ \",$.batches.results[*].values[?(@ > 10)])", BATCH_JSON, "45 _ 34 _ 23 _ 52 _ 12 _ 11 _ 18 _ 22");
verifyFunction(configuration, "$.join(\" \",$.batches.results[*].values[?(@ < 10)], $.batches.results[*].productId)", BATCH_JSON, "2 3 5 4 3 2 1 3 1 23 23");
verifyFunction(configuration, "$.batches.results.join(\" \", $.productId, $.values[?(@ < 10)])", BATCH_JSON, "23 23 2 3 5 4 3 2 1 3 1");
}
}