Skip to content

Commit

Permalink
Fixes cases where we send primitive values over Json RPC (#4751)
Browse files Browse the repository at this point in the history
Signed-off-by: Dmitry Kuleshov <dkuleshov@codenvy.com>
  • Loading branch information
Dmitry Kuleshov authored and Vitalii Parfonov committed Apr 19, 2017
1 parent 3310744 commit a3d2516
Show file tree
Hide file tree
Showing 12 changed files with 293 additions and 188 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -187,15 +187,4 @@ JsonRpcResponse createResponse(@Assisted("id") String id, @Assisted("result") Js
* @return JSON RPC params
*/
JsonRpcParams createParams(@Assisted("params") Object params);

/**
* Create a JSON RPC params instance by passing corresponding values.
* Params should be represented by a list of objects.
*
* @param params
* params list
*
* @return JSON RPC params
*/
JsonRpcParams createParamsList(@Assisted("params") List<?> params);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,88 +21,185 @@
import org.eclipse.che.dto.server.DtoFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.eclipse.che.api.core.jsonrpc.JsonRpcUtils.cast;

/**
* Represents JSON RPC params object. Can be constructed out of
* stringified json object or by passing specific parameters.
* Use {@link JsonRpcFactory#createParams(Object)},
* {@link JsonRpcFactory#createParamsList(List)} or
* {@link JsonRpcFactory#createParams(String)} to get an instance.
*/
public class JsonRpcParams {
private final static JsonObject EMPTY_OBJECT = new JsonObject();
private final JsonParser jsonParser;

private List<JsonElement> paramsList;
private JsonElement params;
private List<Param<?>> params;
private Param<?> param;

@AssistedInject
public JsonRpcParams(@Assisted("message") String message, JsonParser jsonParser) {
this.jsonParser = jsonParser;

checkNotNull(message, "Message must not be null");
checkArgument(!message.isEmpty(), "Message must not be empty");

JsonElement jsonElement = jsonParser.parse(message);
if (jsonElement.isJsonArray()) {
JsonArray jsonArray = jsonParser.parse(message).getAsJsonArray();
paramsList = new ArrayList<>(jsonArray.size());
jsonArray.forEach(it -> paramsList.add(it));
this.params = new ArrayList<>(jsonArray.size());
for (JsonElement element : jsonArray) {
if (element.isJsonPrimitive()) {
JsonPrimitive primitiveElement = element.getAsJsonPrimitive();
Param<?> paramCandidate;
if (primitiveElement.isBoolean()) {
paramCandidate = new Param<>(Boolean.class, primitiveElement.getAsBoolean());
} else if (primitiveElement.isNumber()) {
paramCandidate = new Param<>(Double.class, primitiveElement.getAsDouble());
} else {
paramCandidate = new Param<>(String.class, primitiveElement.getAsString());
}
this.params.add(paramCandidate);
} else {
this.params.add(new Param<>(Object.class, element.getAsJsonObject()));
}
}

this.param = null;
} else if (jsonElement.isJsonPrimitive()) {
JsonPrimitive primitiveElement = jsonElement.getAsJsonPrimitive();
if (primitiveElement.isBoolean()) {
this.param = new Param<>(Boolean.class, primitiveElement.getAsBoolean());
} else if (primitiveElement.isNumber()) {
this.param = new Param<>(Double.class, primitiveElement.getAsDouble());
} else {
this.param = new Param<>(String.class, primitiveElement.getAsString());
}

this.params = null;
} else if (jsonElement.isJsonObject()) {
this.param = new Param<>(Object.class, jsonElement.getAsJsonObject());

this.params = null;
} else {
params = jsonParser.parse(message);
this.params = null;
this.param = null;
}
}

@AssistedInject
public JsonRpcParams(@Assisted("params") Object params, JsonParser jsonParser) {
this.params = params == null ? EMPTY_OBJECT : jsonParser.parse(params.toString());
}

@AssistedInject
public JsonRpcParams(JsonParser jsonParser, @Assisted("params") List<?> params) {
if (params == null || params.isEmpty()) {
this.paramsList = Collections.emptyList();
public JsonRpcParams(JsonParser jsonParser, @Assisted("params") Object params) {
this.jsonParser = jsonParser;

if (params == null) {
this.params = null;
this.param = null;
} else {
// ugly workaround will be fixed in next release
if (params.get(0) instanceof String) {
this.paramsList = params.stream().map(it -> new JsonPrimitive(it.toString())).collect(Collectors.toList());
if (params instanceof List) {
List<?> listParams = (List<?>)params;
this.params = new ArrayList<>(listParams.size());

for (Object param : listParams) {
Param<?> paramCandidate;
if (param instanceof Boolean) {
paramCandidate = new Param<>(Boolean.class, (Boolean)param);
} else if (param instanceof String) {
paramCandidate = new Param<>(String.class, (String)param);
} else if (param instanceof Double) {
paramCandidate = new Param<>(Double.class, (Double)param);
} else {
paramCandidate = new Param<>(Object.class, param);
}
this.params.add(paramCandidate);
}

this.param = null;
} else {
this.paramsList = params.stream().map(Object::toString).map(jsonParser::parse).collect(Collectors.toList());
Param<?> paramCandidate;
if (params instanceof Boolean) {
this.param = new Param<>(Boolean.class, (Boolean)params);
} else if (params instanceof String) {
this.param = new Param<>(String.class, (String)params);
} else if (params instanceof Double) {
this.param = new Param<>(Double.class, (Double)params);
} else {
this.param = new Param<>(Object.class, params);
}

this.params = null;
}
}
}

public boolean emptyOrAbsent() {
return (paramsList == null || paramsList.isEmpty()) && (params == null || EMPTY_OBJECT.equals(params));
return (params == null || params.isEmpty()) && (param == null || jsonParser.parse("{}").equals(param.value));
}

public JsonElement toJsonElement() {
if (params != null) {
return params;
if (param != null) {
if (param.type.equals(Object.class)) {
return jsonParser.parse(param.value.toString());
} else if (param.type.equals(String.class)) {
return new JsonPrimitive((String)param.value);
} else if (param.type.equals(Boolean.class)) {
return new JsonPrimitive((Boolean)param.value);
} else if (param.type.equals(Double.class)) {
return new JsonPrimitive((Double)param.value);
}
}

JsonArray array = new JsonArray();
paramsList.forEach(array::add);
for (Param<?> paramCandidate : params) {
JsonElement element;
if (paramCandidate.type.equals(Object.class)) {
element = jsonParser.parse(paramCandidate.value.toString());
} else if (paramCandidate.type.equals(String.class)) {
element = new JsonPrimitive((String)paramCandidate.value);
} else if (paramCandidate.type.equals(Boolean.class)) {
element = new JsonPrimitive((Boolean)paramCandidate.value);
} else {
element = new JsonPrimitive((Double)paramCandidate.value);
}
array.add(element);
}
return array;
}

public <T> T getAs(Class<T> type) {
checkNotNull(params, "Type must not be null");
checkNotNull(type, "Type must not be null");
checkNotNull(param, "Param must not be null");
checkState(type.equals(param.type), "Types should match");

return JsonRpcUtils.getAs(params, type);
if (param.type.equals(Object.class)) {
return DtoFactory.getInstance().createDtoFromJson(param.value.toString(), type);
} else {
return cast(param.value);
}
}

public <T> List<T> getAsListOf(Class<T> type) {
checkNotNull(type, "Type must not be null");

return JsonRpcUtils.getAsListOf(paramsList, type);
return params.stream().map(it -> it.value).collect(cast(Collectors.toList()));
}

@Override
public String toString() {
return toJsonElement().toString();
}

private class Param<T> {
final private Class<T> type;
final private T value;

private Param(Class<T> type, T value) {
this.type = type;
this.value = value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ public JsonRpcResult handle(String endpointId, JsonRpcParams params) throws Json

LOG.debug("Handling request from: {}, with params: {}", endpointId, params);

P paramsObject = params.getAs(pClass);
P paramsObject = pClass.equals(String.class) ||
pClass.equals(Boolean.class) ||
pClass.equals(Double.class) ? params.getAsListOf(pClass).get(0)
: params.getAs(pClass);

LOG.debug("Created raw params object: {}", paramsObject);
List<R> resultList = function.apply(endpointId, paramsObject);
LOG.debug("Received result list: {}", resultList);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ public JsonRpcResult handle(String endpointId, JsonRpcParams params) throws Json

LOG.debug("Handling request from: {}, with params: {}", endpointId, params);

P paramsObject = params.getAs(pClass);
P paramsObject = pClass.equals(String.class) ||
pClass.equals(Boolean.class) ||
pClass.equals(Double.class) ? params.getAsListOf(pClass).get(0)
: params.getAs(pClass);

LOG.debug("Created raw params object: {}", paramsObject);
R result = function.apply(endpointId, paramsObject);
LOG.debug("Received result: {}", result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public JsonRpcPromise<Void> sendAndReceiveResultAsEmpty() {
}

private void transmitNotification() {
JsonRpcParams params = factory.createParamsList(pListValue);
JsonRpcParams params = factory.createParams(pListValue);
JsonRpcRequest request = factory.createRequest(method, params);
transmitter.transmit(endpointId, request.toString());
}
Expand All @@ -176,7 +176,7 @@ private String transmitRequest() {
Integer id = MethodNameConfigurator.id.incrementAndGet();
String requestId = id.toString();

JsonRpcParams params = factory.createParamsList(pListValue);
JsonRpcParams params = factory.createParams(pListValue);
JsonRpcRequest request = factory.createRequest(requestId, method, params);
transmitter.transmit(endpointId, request.toString());
return requestId;
Expand Down
Loading

0 comments on commit a3d2516

Please sign in to comment.