blob: c79cb81899f767d1bddd84b4569811b26aa9b758 [file] [log] [blame]
package com.intellij.tasks.generic;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.xmlb.annotations.Tag;
import com.jayway.jsonpath.InvalidPathException;
import com.jayway.jsonpath.JsonPath;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
/**
* @author Mikhail Golubev
*/
@Tag("JsonResponseHandler")
public final class JsonPathResponseHandler extends SelectorBasedResponseHandler {
private static final Map<Class<?>, String> JSON_TYPES = ContainerUtil.newHashMap(
new Pair<Class<?>, String>(Map.class, "JSON object"),
new Pair<Class<?>, String>(List.class, "JSON array"),
new Pair<Class<?>, String>(String.class, "JSON string"),
new Pair<Class<?>, String>(Integer.class, "JSON number"),
new Pair<Class<?>, String>(Double.class, "JSON number"),
new Pair<Class<?>, String>(Boolean.class, "JSON boolean")
);
private final Map<String, JsonPath> myCompiledCache = new HashMap<String, JsonPath>();
/**
* Serialization constructor
*/
@SuppressWarnings("UnusedDeclaration")
public JsonPathResponseHandler() {
}
public JsonPathResponseHandler(GenericRepository repository) {
super(repository);
}
@Nullable
private Object extractRawValue(@NotNull Selector selector, @NotNull String source) throws Exception {
if (StringUtil.isEmpty(selector.getPath())) {
return null;
}
JsonPath jsonPath = lazyCompile(selector.getPath());
Object value;
try {
value = jsonPath.read(source);
}
catch (InvalidPathException e) {
throw new Exception(String.format("JsonPath expression '%s' doesn't match", selector.getPath()), e);
}
if (value == null) {
return null;
}
return value;
}
@Nullable
private <T> T extractValueAndCheckType(@NotNull Selector selector, @NotNull String source, Class<T> cls) throws Exception {
final Object value = extractRawValue(selector, source);
if (value == null) {
return null;
}
if (!(cls.isInstance(value))) {
throw new Exception(
String.format("JsonPath expression '%s' should match %s. Got '%s' instead",
selector.getPath(), JSON_TYPES.get(cls), value));
}
@SuppressWarnings("unchecked")
T casted = (T)value;
return casted;
}
@NotNull
@Override
protected List<Object> selectTasksList(@NotNull String response, int max) throws Exception {
@SuppressWarnings("unchecked")
List<Object> list = (List<Object>)extractValueAndCheckType(getSelector(TASKS), response, List.class);
if (list == null) {
return ContainerUtil.emptyList();
}
return ContainerUtil.map2List(list, new Function<Object, Object>() {
@Override
public Object fun(Object o) {
return o.toString();
}
}).subList(0, Math.min(list.size(), max));
}
@Nullable
@Override
protected String selectString(@NotNull Selector selector, @NotNull Object context) throws Exception {
//return extractValueAndCheckType((String)context, selector, String.class);
final Object value = extractRawValue(selector, (String)context);
if (value == null) {
return null;
}
if (value instanceof String || value instanceof Number || value instanceof Boolean) {
return value.toString();
}
throw new Exception(String.format("JsonPath expression '%s' should match string value. Got '%s' instead",
selector.getPath(), value));
}
@Nullable
@Override
protected Boolean selectBoolean(@NotNull Selector selector, @NotNull Object context) throws Exception {
return extractValueAndCheckType(selector, (String)context, Boolean.class);
}
@SuppressWarnings("UnusedDeclaration")
@Nullable
private Long selectLong(@NotNull Selector selector, @NotNull String source) throws Exception {
return extractValueAndCheckType(selector, source, Long.class);
}
@NotNull
private JsonPath lazyCompile(@NotNull String path) throws Exception {
JsonPath jsonPath = myCompiledCache.get(path);
if (jsonPath == null) {
try {
jsonPath = JsonPath.compile(path);
myCompiledCache.put(path, jsonPath);
}
catch (InvalidPathException e) {
throw new Exception(String.format("Malformed JsonPath expression '%s'", path));
}
}
return jsonPath;
}
@NotNull
@Override
public ResponseType getResponseType() {
return ResponseType.JSON;
}
}