Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.kurento.jsonrpc.JsonUtils Maven / Gradle / Ivy
/*
* (C) Copyright 2013 Kurento (http://kurento.org/)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.kurento.jsonrpc;
import static org.kurento.jsonrpc.internal.JsonRpcConstants.DATA_PROPERTY;
import static org.kurento.jsonrpc.internal.JsonRpcConstants.ERROR_PROPERTY;
import static org.kurento.jsonrpc.internal.JsonRpcConstants.ID_PROPERTY;
import static org.kurento.jsonrpc.internal.JsonRpcConstants.JSON_RPC_PROPERTY;
import static org.kurento.jsonrpc.internal.JsonRpcConstants.METHOD_PROPERTY;
import static org.kurento.jsonrpc.internal.JsonRpcConstants.PARAMS_PROPERTY;
import static org.kurento.jsonrpc.internal.JsonRpcConstants.RESULT_PROPERTY;
import static org.kurento.jsonrpc.internal.JsonRpcConstants.SESSION_ID_PROPERTY;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.kurento.jsonrpc.internal.JsonRpcConstants;
import org.kurento.jsonrpc.message.Message;
import org.kurento.jsonrpc.message.Request;
import org.kurento.jsonrpc.message.Response;
import org.kurento.jsonrpc.message.ResponseError;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.JsonSyntaxException;
import com.google.gson.internal.$Gson$Types;
/**
*
* Gson/JSON utilities; used to serialise Java object to JSON (as String).
*
* @author Miguel París ([email protected] )
* @since 1.0.0
*/
public class JsonUtils {
public static final boolean INJECT_SESSION_ID = true;
/**
* Static instance of Gson object.
*/
private static Gson gson;
/**
* Serialise Java object to JSON (as String).
*
* @param obj
* Java Object representing a JSON message to be serialized
* @return Serialised JSON message (as String)
*/
public static String toJson(Object obj) {
return getGson().toJson(obj);
}
public static JsonObject toJsonObject(Object obj) {
// TODO Optimise this implementation if possible
return fromJson(getGson().toJson(obj), JsonObject.class);
}
public static Message fromJsonMessage(String message) {
JsonObject json = fromJson(message, JsonObject.class);
if (json.has(METHOD_PROPERTY)) {
return fromJsonRequest(json, JsonObject.class);
} else {
return fromJsonResponse(json, JsonElement.class);
}
}
public static Request fromJsonRequest(String json, Class paramsClass) {
if (INJECT_SESSION_ID) {
// TODO Optimise this implementation if possible
return fromJsonRequestInject(fromJson(json, JsonObject.class), paramsClass);
}
return getGson().fromJson(json,
$Gson$Types.newParameterizedTypeWithOwner(null, Request.class, paramsClass));
}
public static Response fromJsonResponse(String json, Class resultClass) {
if (INJECT_SESSION_ID) {
// TODO Optimise this implementation if possible
return fromJsonResponseInject(fromJson(json, JsonObject.class), resultClass);
}
try {
return getGson().fromJson(json,
$Gson$Types.newParameterizedTypeWithOwner(null, Response.class, resultClass));
} catch (JsonSyntaxException e) {
throw new JsonRpcException("Exception converting Json '" + json
+ "' to a JSON-RPC response with params as class " + resultClass.getName(), e);
}
}
public static Request fromJsonRequest(JsonObject json, Class paramsClass) {
if (INJECT_SESSION_ID) {
// TODO Optimise this implementation if possible
return fromJsonRequestInject(json, paramsClass);
}
return getGson().fromJson(json,
$Gson$Types.newParameterizedTypeWithOwner(null, Request.class, paramsClass));
}
public static Response fromJsonResponse(JsonObject json, Class resultClass) {
if (INJECT_SESSION_ID) {
// TODO Optimize this implementation if possible
return fromJsonResponseInject(json, resultClass);
}
return getGson().fromJson(json,
$Gson$Types.newParameterizedTypeWithOwner(null, Response.class, resultClass));
}
private static Response fromJsonResponseInject(JsonObject jsonObject,
Class resultClass) {
try {
String sessionId = extractSessionId(jsonObject, RESULT_PROPERTY);
Response response;
if (resultClass != null) {
response = JsonUtils.fromJson(jsonObject,
$Gson$Types.newParameterizedTypeWithOwner(null, Response.class, resultClass));
} else {
response = JsonUtils.fromJson(jsonObject,
$Gson$Types.newParameterizedTypeWithOwner(null, Response.class, JsonElement.class));
}
response.setSessionId(sessionId);
return response;
} catch (JsonSyntaxException e) {
throw new JsonRpcException("Exception converting Json '" + jsonObject
+ "' to a JSON-RPC response with params as class " + resultClass.getName(), e);
}
}
private static Request fromJsonRequestInject(JsonObject jsonObject, Class paramsClass) {
String sessionId = extractSessionId(jsonObject, PARAMS_PROPERTY);
Request request = getGson().fromJson(jsonObject,
$Gson$Types.newParameterizedTypeWithOwner(null, Request.class, paramsClass));
request.setSessionId(sessionId);
return request;
}
private static String extractSessionId(JsonObject jsonObject, String memberName) {
JsonElement responseJson = jsonObject.get(memberName);
if (responseJson != null && responseJson.isJsonObject()) {
JsonObject responseJsonObject = (JsonObject) responseJson;
JsonElement sessionIdJson = responseJsonObject.remove(SESSION_ID_PROPERTY);
if (sessionIdJson != null && !(sessionIdJson instanceof JsonNull)) {
return sessionIdJson.getAsString();
}
}
return null;
}
public static String toJson(Object obj, Type type) {
return getGson().toJson(obj, type);
}
public static String toJsonRequest(Request request) {
return getGson().toJson(request, $Gson$Types.newParameterizedTypeWithOwner(null, Request.class,
getClassOrNull(request.getParams())));
}
public static String toJsonResponse(Response request) {
return getGson().toJson(request, $Gson$Types.newParameterizedTypeWithOwner(null, Response.class,
getClassOrNull(request.getResult())));
}
public static T fromJson(String json, Class clazz) {
return getGson().fromJson(json, clazz);
}
public static T fromJson(JsonElement json, Class clazz) {
return getGson().fromJson(json, clazz);
}
public static T fromJson(String json, Type type) {
return getGson().fromJson(json, type);
}
public static T fromJson(JsonElement json, Type type) {
return getGson().fromJson(json, type);
}
private static Class> getClassOrNull(Object object) {
return object == null ? null : object.getClass();
}
/**
* Gson object accessor (getter).
*
* @return son object
*/
public static Gson getGson() {
if (gson == null) {
synchronized (JsonUtils.class) {
if (gson == null) {
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Request.class, new JsonRpcRequestDeserializer());
builder.registerTypeAdapter(Response.class, new JsonRpcResponseDeserializer());
builder.registerTypeAdapter(Props.class, new JsonPropsAdapter());
builder.disableHtmlEscaping();
gson = builder.create();
}
}
}
return gson;
}
static boolean isIn(JsonObject jObject, String[] clues) {
for (String clue : clues) {
if (jObject.has(clue)) {
return true;
}
}
return false;
}
public static String toJsonMessage(Message message) {
if (message.getSessionId() != null && INJECT_SESSION_ID) {
JsonObject jsonObject = JsonUtils.toJsonObject(message);
JsonObject objectToInjectSessionId;
if (message instanceof Request) {
objectToInjectSessionId = convertToObject(jsonObject, PARAMS_PROPERTY);
} else {
Response> response = (Response>) message;
if (response.getError() == null) {
objectToInjectSessionId = convertToObject(jsonObject, RESULT_PROPERTY);
} else {
objectToInjectSessionId = convertToObject(jsonObject, ERROR_PROPERTY, DATA_PROPERTY);
}
}
objectToInjectSessionId.addProperty(JsonRpcConstants.SESSION_ID_PROPERTY,
message.getSessionId());
return jsonObject.toString();
}
return JsonUtils.toJson(message);
}
private static JsonObject convertToObject(JsonObject jsonObject, String... properties) {
String property = properties[0];
JsonElement paramsJson = jsonObject.get(property);
JsonObject paramsAsObject = null;
if (paramsJson == null) {
paramsAsObject = new JsonObject();
jsonObject.add(property, paramsAsObject);
paramsJson = paramsAsObject;
}
if (!paramsJson.isJsonObject()) {
paramsAsObject = new JsonObject();
paramsAsObject.add("value", paramsJson);
jsonObject.add(property, paramsAsObject);
} else {
paramsAsObject = (JsonObject) paramsJson;
}
if (properties.length > 1) {
convertToObject(jsonObject, Arrays.copyOfRange(properties, 1, properties.length));
}
return paramsAsObject;
}
public static JsonElement toJsonElement(Object object) {
return getGson().toJsonTree(object);
}
public static E extractJavaValueFromResult(JsonElement result, Type type) {
if (type == Void.class || type == void.class) {
return null;
}
JsonElement extractResult = extractJsonValueFromResponse(result, type);
return JsonUtils.fromJson(extractResult, type);
}
private static JsonElement extractJsonValueFromResponse(JsonElement result, Type type) {
if (result == null) {
return null;
}
if (isPrimitiveClass(type) || isEnum(type)) {
if (result instanceof JsonPrimitive) {
return result;
} else if (result instanceof JsonArray) {
throw new JsonRpcException(
"Json array '" + result + " cannot be converted to " + getTypeName(type));
} else if (result instanceof JsonObject) {
return extractSimpleValueFromJsonObject((JsonObject) result, type);
} else {
throw new JsonRpcException("Unrecognized json element: " + result);
}
} else if (isList(type)) {
if (result instanceof JsonArray) {
return result;
}
return extractSimpleValueFromJsonObject((JsonObject) result, type);
} else {
return result;
}
}
private static JsonElement extractSimpleValueFromJsonObject(JsonObject result, Type type) {
if (!result.has("value")) {
throw new JsonRpcException("Json object " + result + " cannot be converted to "
+ getTypeName(type) + " without a 'value' property");
}
return result.get("value");
}
private static boolean isEnum(Type type) {
if (type instanceof Class) {
Class> clazz = (Class>) type;
return clazz.isEnum();
}
return false;
}
private static boolean isPrimitiveClass(Type type) {
return type == String.class
|| type == Void.class
|| type == void.class
|| type == Boolean.class
|| type == boolean.class
|| type == Integer.class
|| type == int.class
|| type == Long.class
|| type == long.class
|| type == Float.class
|| type == float.class
|| type == Double.class
|| type == double.class;
}
private static boolean isList(Type type) {
if (type == List.class) {
return true;
}
if (type instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) type;
if (pType.getRawType() instanceof Class) {
return ((Class>) pType.getRawType()).isAssignableFrom(List.class);
}
}
return false;
}
private static String getTypeName(Type type) {
if (type instanceof Class) {
Class> clazz = (Class>) type;
return clazz.getSimpleName();
} else if (type instanceof ParameterizedType) {
StringBuilder sb = new StringBuilder();
ParameterizedType pType = (ParameterizedType) type;
Class> rawClass = (Class>) pType.getRawType();
sb.append(rawClass.getSimpleName());
Type[] arguments = pType.getActualTypeArguments();
if (arguments.length > 0) {
sb.append('<');
for (Type aType : arguments) {
sb.append(getTypeName(aType));
sb.append(',');
}
sb.deleteCharAt(sb.length() - 1);
sb.append('>');
}
return sb.toString();
}
return type.toString();
}
public static List toStringList(JsonArray values) {
List list = new ArrayList<>();
for (JsonElement element : values) {
if (element instanceof JsonPrimitive) {
list.add(((JsonPrimitive) element).getAsString());
} else {
throw new JsonParseException("JsonArray " + values + " contains non string elements");
}
}
return list;
}
}
class JsonRpcResponseDeserializer implements JsonDeserializer> {
private static final Logger log = LoggerFactory.getLogger(JsonRpcResponseDeserializer.class);
@Override
public Response> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
if (!(json instanceof JsonObject)) {
throw new JsonParseException("JonObject expected, found " + json.getClass().getSimpleName());
}
JsonObject jObject = (JsonObject) json;
if (!jObject.has(JSON_RPC_PROPERTY)) {
throw new JsonParseException(
"Invalid JsonRpc response lacking version '" + JSON_RPC_PROPERTY + "' field");
}
if (!jObject.get(JSON_RPC_PROPERTY).getAsString().equals(JsonRpcConstants.JSON_RPC_VERSION)) {
throw new JsonParseException("Invalid JsonRpc version");
}
Integer id = null;
JsonElement idAsJsonElement = jObject.get(ID_PROPERTY);
if (idAsJsonElement != null) {
try {
id = Integer.valueOf(idAsJsonElement.getAsInt());
} catch (Exception e) {
throw new JsonParseException(
"Invalid format in '" + ID_PROPERTY + "' field in request " + json);
}
}
if (jObject.has(ERROR_PROPERTY)) {
return new Response<>(id,
(ResponseError) context.deserialize(jObject.get(ERROR_PROPERTY), ResponseError.class));
} else {
if (jObject.has(RESULT_PROPERTY)) {
ParameterizedType parameterizedType = (ParameterizedType) typeOfT;
Object deserialize = context.deserialize(jObject.get(RESULT_PROPERTY),
parameterizedType.getActualTypeArguments()[0]);
return new Response<>(id, deserialize);
} else {
log.warn("Invalid JsonRpc response: " + json + " It lacks a valid '" + RESULT_PROPERTY
+ "' or '" + ERROR_PROPERTY + "' field");
return new Response<>(id, null);
}
}
}
}
class JsonRpcRequestDeserializer implements JsonDeserializer> {
@Override
public Request> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
if (!(json instanceof JsonObject)) {
throw new JsonParseException(
"Invalid JsonRpc request showning JsonElement type " + json.getClass().getSimpleName());
}
JsonObject jObject = (JsonObject) json;
// FIXME: Enable again when KMS sends jsonrpc field in register message
// if (!jObject.has(JSON_RPC_PROPERTY)) {
// throw new JsonParseException(
// "Invalid JsonRpc request lacking version '"
// + JSON_RPC_PROPERTY + "' field");
// }
//
// if (!jObject.get("jsonrpc").getAsString().equals(JSON_RPC_VERSION)) {
// throw new JsonParseException("Invalid JsonRpc version");
// }
if (!jObject.has(METHOD_PROPERTY)) {
throw new JsonParseException(
"Invalid JsonRpc request lacking '" + METHOD_PROPERTY + "' field");
}
Integer id = null;
if (jObject.has(ID_PROPERTY)) {
id = Integer.valueOf(jObject.get(ID_PROPERTY).getAsInt());
}
ParameterizedType parameterizedType = (ParameterizedType) typeOfT;
return new Request<>(id, jObject.get(METHOD_PROPERTY).getAsString(), context
.deserialize(jObject.get(PARAMS_PROPERTY), parameterizedType.getActualTypeArguments()[0]));
}
}
class JsonPropsAdapter implements JsonDeserializer, JsonSerializer {
@Override
public Props deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
if (!(json instanceof JsonObject)) {
throw new JsonParseException("Cannot convert " + json + " to Props object");
}
JsonObject jObject = (JsonObject) json;
Props props = new Props();
for (Map.Entry e : jObject.entrySet()) {
Object value = deserialize(e.getValue(), context);
props.add(e.getKey(), value);
}
return props;
}
private Object deserialize(JsonElement value, JsonDeserializationContext context) {
if (value instanceof JsonObject) {
return deserialize(value, null, context);
} else if (value instanceof JsonPrimitive) {
return toPrimitiveObject(value);
} else if (value instanceof JsonArray) {
JsonArray array = (JsonArray) value;
List result = new ArrayList<>();
for (JsonElement element : array) {
result.add(deserialize(element, context));
}
return result;
} else if (value instanceof JsonNull) {
return null;
} else {
throw new JsonRpcException("Unrecognized Json element: " + value);
}
}
public Object toPrimitiveObject(JsonElement element) {
JsonPrimitive primitive = (JsonPrimitive) element;
if (primitive.isBoolean()) {
return Boolean.valueOf(primitive.getAsBoolean());
} else if (primitive.isNumber()) {
Number number = primitive.getAsNumber();
double value = number.doubleValue();
if ((int) value == value) {
return Integer.valueOf((int) value);
} else if ((long) value == value) {
return Long.valueOf((long) value);
} else if ((float) value == value) {
return Float.valueOf((float) value);
} else {
return Double.valueOf((double) value);
}
} else if (primitive.isString()) {
return primitive.getAsString();
} else {
throw new JsonRpcException("Unrecognized JsonPrimitive: " + primitive);
}
}
@Override
public JsonElement serialize(Props props, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jsonObject = new JsonObject();
for (Prop prop : props) {
jsonObject.add(prop.getName(), context.serialize(prop.getValue()));
}
return jsonObject;
}
}