DATACMNS-885 - Workaround for bug in Jayway's JSONPath array access.

When a recursive decent operator is used in a JSON Path expression there's no way to get out of the array mode again to indicate one is interested in a particular element (e.g. "the first one no matter where in the document") [0]. We now work around this by always letting the parser return lists, so that the mapping library finally kicking in can be equipped with the correct target type to create.

Unfortunately this causes arrays to be double-wrapped for definite paths so that we basically have to adapt the type handed to Jackson in another round to the unwrap the mapping result in turn [1].

[0] https://github.com/jayway/JsonPath/issues/248
[1] https://github.com/jayway/JsonPath/issues/249
This commit is contained in:
Oliver Gierke
2016-07-18 12:32:59 +02:00
parent eec2b43fd0
commit 762a12b4a2
2 changed files with 38 additions and 2 deletions

View File

@@ -22,6 +22,8 @@ import net.minidev.json.JSONObject;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.aopalliance.intercept.MethodInterceptor;
@@ -38,6 +40,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.ParseContext;
import com.jayway.jsonpath.TypeRef;
import com.jayway.jsonpath.spi.mapper.MappingProvider;
@@ -63,6 +66,7 @@ public class JsonProjectingMethodInterceptorFactory implements MethodInterceptor
Assert.notNull(mappingProvider, "MappingProvider must not be null!");
Configuration build = Configuration.builder()//
.options(Option.ALWAYS_RETURN_LIST)//
.mappingProvider(mappingProvider)//
.build();
@@ -131,8 +135,24 @@ public class JsonProjectingMethodInterceptorFactory implements MethodInterceptor
ResolvableType type = ResolvableType.forMethodReturnType(method);
String jsonPath = getJsonPath(method);
return !returnType.getActualType().getType().isInterface() ? context.read(jsonPath, new ResolvableTypeRef(type))
: context.read(jsonPath);
if (returnType.getActualType().getType().isInterface()) {
List<?> result = context.read(jsonPath);
return result.isEmpty() ? null : result.get(0);
}
boolean isCollectionResult = Collection.class.isAssignableFrom(type.getRawClass());
type = isCollectionResult ? type : ResolvableType.forClassWithGenerics(List.class, type);
type = isCollectionResult && JsonPath.isPathDefinite(jsonPath)
? ResolvableType.forClassWithGenerics(List.class, type) : type;
List<?> result = (List<?>) context.read(jsonPath, new ResolvableTypeRef(type));
if (isCollectionResult && JsonPath.isPathDefinite(jsonPath)) {
result = (List<?>) result.get(0);
}
return isCollectionResult ? result : result.isEmpty() ? null : result.get(0);
}
/**