class StringToNumberDecoder implements RpcDecoder {

    @Override
    public <T> T decode(JsonValue value, Class<T> type)
            throws RpcDecodeException {
        String stringValue = value.asString();
        try {
            Number number = parseNumber(stringValue);
            if (Number.class.equals(type)) {
                return type.cast(number);
            }
            Field requiredType = type.getField("TYPE");
            Class<?> primitiveRequiredType = (Class<?>) requiredType.get(null);
            Method method = Number.class
                    .getMethod(primitiveRequiredType + "Value");
            T result = type.cast(method.invoke(number));
            if (number.equals(parseNumber(result.toString()))) {
                // check whether the number is the same after the projection
                // (applying the "xxxValue" method)
                return result;
            } else {
                throw new RpcDecodeException(
                        String.format("Can't decode '%s' to type '%s'",
                                stringValue, type.getName()));
            }
        } catch (ParseException exception) {
            throw new RpcDecodeException(exception);
        } catch (NoSuchFieldException | SecurityException
                | IllegalAccessException | IllegalArgumentException
                | NoSuchMethodException | InvocationTargetException exception) {
            // can't happen
            throw new RuntimeException(exception);
        }
    }

}