Invalid type error when calling a function where one of the types is Json.
Opened this issue · 3 comments
Have a call that is defined in the following manner:
using Json = nlohmann::json;
using JsonPointer = nlohmann::json_pointer;
Json SomeStruct::setProperty(const JsonPointer &pointer, const Json &value)
{
Json j;
to_json(j, *this);
j[pointer] = value;
from_json(j, *this);
}It's used in a manner to allow independent values within a class/struct that can be converted to_json(json, SomeStruct) and allow the property to be changed. - So using the Json type as a variant of what is allowed and then converting and reconverting the values to allow the API to identify a single value to change.
The problem I have is when I do the following:
const std::function<Json(const std::string &, const Json &)> setPropertyFn = [this](const std ::string &pointer,
const Json &value) {
auto result = m_myStruct->setProperty(JsonPointer(pointer), value);
};
addRpc("struct.setProperty", GetHandle(setPropertyFn), {"pointer", "value"});When I send the following for example:
{"id":8,"jsonrpc":"2.0","method":"struct.setProperty","params":["/type/subtype/subtype2/value",20]}I get the return of:
{"error":{"code":-32602,"message":"invalid parameter: must be object, but is unsigned integer for parameter \"value\""},"id":8,"jsonrpc":"2.0"}But there should be no comparison needed as the param_type is already json.
Suggest changing:
template<typename T>
inline void check_param_type...- inline void check_param_type(...) { /* No type checks just pass it along */}
- rest operate as expected.
The following changes to check_param_type fixes this issue:
template <typename T>
inline void check_param_type(size_t index, const json &x, json::value_t expectedType, typename std::enable_if<std::is_same<T, json>::value>::type * = 0) {
// No checking if type is Json - already json.
}
template <typename T>
inline void check_param_type(size_t index, const json &x, json::value_t expectedType,
typename std::enable_if<std::is_arithmetic<T>::value && !std::is_same<T, json>::value>::type * = 0) {
if (expectedType == json::value_t::number_unsigned && x.type() == json::value_t::number_integer) {
if (x.get<long long int>() < 0)
throw JsonRpcException(invalid_params, "invalid parameter: must be " + type_name(expectedType) + ", but is " + type_name(x.type()), index);
} else if (x.type() == json::value_t::number_unsigned && expectedType == json::value_t::number_integer) {
if (x.get<long long unsigned>() > (long long unsigned)std::numeric_limits<T>::max()) {
throw JsonRpcException(invalid_params, "invalid parameter: exceeds value range of " + type_name(expectedType), index);
}
} else if ((x.type() == json::value_t::number_unsigned || x.type() == json::value_t::number_integer) && expectedType == json::value_t::number_float) {
if (static_cast<long long int>(x.get<double>()) != x.get<long long int>()) {
throw JsonRpcException(invalid_params, "invalid parameter: exceeds value range of " + type_name(expectedType), index);
}
} else if (x.type() != expectedType) {
throw JsonRpcException(invalid_params, "invalid parameter: must be " + type_name(expectedType) + ", but is " + type_name(x.type()), index);
}
}
template <typename T>
inline void check_param_type(size_t index, const json &x, json::value_t expectedType,
typename std::enable_if<!std::is_arithmetic<T>::value && !std::is_same<T, json>::value>::type * = 0) {
if (x.type() != expectedType) {
throw JsonRpcException(invalid_params, "invalid parameter: must be " + type_name(expectedType) + ", but is " + type_name(x.type()), index);
}
}Also note this is hard to read - suggest improving since you are using C++17 and above:
template <typename T>
inline void check_param_type(size_t index, const json &x, json::value_t expectedType) {
if constexpr (std::is_same_v<T, json>) {
// No checking if type is Json - already json.
return;
} else if constexpr (std::is_arithmetic_v<T>) {
if (expectedType == json::value_t::number_unsigned && x.type() == json::value_t::number_integer) {
if (x.get<long long int>() < 0)
throw JsonRpcException(invalid_params, "invalid parameter: must be " + type_name(expectedType) + ", but is " + type_name(x.type()), index);
} else if (x.type() == json::value_t::number_unsigned && expectedType == json::value_t::number_integer) {
if (x.get<long long unsigned>() > (long long unsigned)std::numeric_limits<T>::max()) {
throw JsonRpcException(invalid_params, "invalid parameter: exceeds value range of " + type_name(expectedType), index);
}
} else if ((x.type() == json::value_t::number_unsigned || x.type() == json::value_t::number_integer) && expectedType == json::value_t::number_float) {
if (static_cast<long long int>(x.get<double>()) != x.get<long long int>()) {
throw JsonRpcException(invalid_params, "invalid parameter: exceeds value range of " + type_name(expectedType), index);
}
} else if (x.type() != expectedType) {
throw JsonRpcException(invalid_params, "invalid parameter: must be " + type_name(expectedType) + ", but is " + type_name(x.type()), index);
}
} else {
if (x.type() != expectedType) {
throw JsonRpcException(invalid_params, "invalid parameter: must be " + type_name(expectedType) + ", but is " + type_name(x.type()), index);
}
}
}Adding Patch File: Cannot push a branch: