/******************************************************************************* | |
* Copyright (c) 2014 - 2018 Orange. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License 2.0 | |
* which accompanies this distribution, and is available at | |
* https://www.eclipse.org/legal/epl-2.0/ | |
* | |
* Contributors: | |
* BAREAU Cyrille <cyrille.bareau@orange.com>, | |
* BONNARDEL Gregory <gbonnardel.ext@orange.com>, | |
*******************************************************************************/ | |
package org.eclipse.om2m.persistence.mongodb.resource; | |
import java.lang.reflect.InvocationTargetException; | |
import java.lang.reflect.Method; | |
import java.lang.reflect.ParameterizedType; | |
import java.lang.reflect.Type; | |
import java.math.BigInteger; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.Map.Entry; | |
import org.apache.commons.logging.Log; | |
import org.apache.commons.logging.LogFactory; | |
import org.eclipse.om2m.commons.constants.ResourceType; | |
import org.eclipse.om2m.commons.entities.AccessControlPolicyEntity; | |
import org.eclipse.om2m.commons.entities.AeAnncEntity; | |
import org.eclipse.om2m.commons.entities.AeEntity; | |
import org.eclipse.om2m.commons.entities.CSEBaseEntity; | |
import org.eclipse.om2m.commons.entities.ContainerEntity; | |
import org.eclipse.om2m.commons.entities.ContentInstanceEntity; | |
import org.eclipse.om2m.commons.entities.DynamicAuthorizationConsultationEntity; | |
import org.eclipse.om2m.commons.entities.FlexContainerAnncEntity; | |
import org.eclipse.om2m.commons.entities.FlexContainerEntity; | |
import org.eclipse.om2m.commons.entities.MgmtObjAnncEntity; | |
import org.eclipse.om2m.commons.entities.MgmtObjEntity; | |
import org.eclipse.om2m.commons.entities.NodeAnncEntity; | |
import org.eclipse.om2m.commons.entities.NodeEntity; | |
import org.eclipse.om2m.commons.entities.RemoteCSEEntity; | |
import org.eclipse.om2m.commons.entities.ResourceEntity; | |
import org.eclipse.om2m.persistence.mongodb.Constants; | |
import com.google.gson.JsonArray; | |
import com.google.gson.JsonDeserializationContext; | |
import com.google.gson.JsonDeserializer; | |
import com.google.gson.JsonElement; | |
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; | |
@SuppressWarnings("unchecked") | |
public class ResourceSerializerDeserializer<T extends ResourceEntity> | |
implements Constants, JsonSerializer<T>, JsonDeserializer<T> { | |
private static final Log LOGGER = LogFactory.getLog(ResourceSerializerDeserializer.class); | |
private static final String GET = "get"; | |
private static final String IS = "is"; | |
private static final String SET = "set"; | |
@Override | |
public JsonElement serialize(T entity, Type xxx, JsonSerializationContext ctxt) { | |
LOGGER.debug(" * IN * serialize " + entity); | |
JsonObject json = new JsonObject(); | |
for (Method method : entity.getClass().getMethods()) { | |
if (!(method.getName().startsWith(GET) || method.getName().startsWith(IS)) | |
|| method.getName().equals("getClass")) { | |
continue; | |
} | |
// at this point, the selected method is a getter | |
String propertyName = method.getName().startsWith(GET) | |
? method.getName().substring(3) | |
: method.getName().substring(2); // method name starts with "is" | |
// check if the return type is primitive | |
boolean isPrimitive = isSuperPrimitive(method.getReturnType()); | |
LOGGER.debug("serialize (method=" + method.getName() + ") - returnType=" | |
+ method.getReturnType() + " - isPrimitive=" + isPrimitive); | |
if (isPrimitive) { | |
try { | |
Object result = method.invoke(entity, new Object[0]); | |
LOGGER.debug("serialize (method=" + method.getName() + ") - invoke result=" + result); | |
json.add(propertyName, ctxt.serialize(result)); | |
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { | |
LOGGER.warn("", e); | |
} | |
} else if (ResourceEntity.class.isAssignableFrom(method.getReturnType())) { | |
LOGGER.debug("Directly assignable to ResourceEntity " + method.getName()); | |
} else if (List.class.equals(method.getReturnType())) { | |
// list | |
try { | |
List<?> result = (List<?>) method.invoke(entity, new Object[0]); | |
JsonArray jsonArray = new JsonArray(); | |
LOGGER.debug("List serialize (method=" + method.getName() | |
+ ") - invoke result=" + result); | |
Type type = method.getGenericReturnType(); | |
if (! ParameterizedType.class.isAssignableFrom(type.getClass())) { | |
continue; | |
} | |
ParameterizedType pt = (ParameterizedType) type; | |
if (pt.getActualTypeArguments().length == 0) { | |
continue; | |
} | |
if (ResourceEntity.class.isAssignableFrom((Class<?>) pt.getActualTypeArguments()[0])) { | |
LOGGER.debug("ComponentType =" + pt.getActualTypeArguments()[0]); | |
// continue; | |
if (result != null) { | |
for (Object obj : result) { | |
if (obj != null) { | |
ResourceEntity resourceEntity = (ResourceEntity) obj; | |
JsonObject jsonObject = new JsonObject(); | |
jsonObject.add(RES_ID, new JsonPrimitive(resourceEntity.getResourceID())); | |
jsonObject.add(RES_TYPE, new JsonPrimitive(resourceEntity.getResourceType())); | |
if (obj instanceof MgmtObjEntity) { | |
jsonObject.add(MGMT_DEF, | |
new JsonPrimitive(((MgmtObjEntity)obj).getMgmtDefinition())); | |
} else if (obj instanceof MgmtObjAnncEntity) { | |
jsonObject.add(MGMT_DEF, | |
new JsonPrimitive(((MgmtObjAnncEntity)obj).getMgmtDefinition())); | |
} | |
jsonArray.add(jsonObject); | |
} | |
} | |
} | |
propertyName = "#" + propertyName; | |
} else { | |
jsonArray = (JsonArray) ctxt.serialize(result); | |
} | |
json.add(propertyName, jsonArray); | |
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { | |
LOGGER.warn("", e); | |
} | |
} | |
} | |
LOGGER.debug(" * OUT * serialize " + json); | |
return json; | |
} | |
private static boolean isSuperPrimitive(Class<?> clazz) { | |
return clazz.isPrimitive() || clazz.getName().startsWith("java.lang.") | |
|| clazz.getName().startsWith("java.math."); | |
} | |
@Override | |
public T deserialize(JsonElement obj, Type xxx, JsonDeserializationContext ctxt) | |
throws JsonParseException { | |
LOGGER.debug(" * IN * deserialize " + obj); | |
// we are sure obj is a Json object | |
JsonObject jsonObject = (JsonObject) obj; | |
// retrieve resource type | |
T entity = create(jsonObject); | |
if (entity == null) { | |
return null; | |
} | |
entity.setResourceType(jsonObject.get(RES_TYPE).getAsBigInteger()); | |
for (Entry<String, JsonElement> entry : jsonObject.entrySet()) { | |
String propertyName = entry.getKey(); | |
JsonElement value = entry.getValue(); | |
if (propertyName.equals(RES_TYPE)) { | |
continue; | |
} | |
if (value.isJsonPrimitive()) { | |
JsonPrimitive jsonPrimitive = (JsonPrimitive) value; | |
Object param = null; | |
Method setterMethod = getSetter(propertyName, entity.getClass()); | |
// identify setter | |
if (setterMethod == null) { | |
LOGGER.debug("Setter not found for " + propertyName); | |
} else { | |
if (jsonPrimitive.isBoolean()) { | |
param = jsonPrimitive.getAsBoolean(); | |
} else if (jsonPrimitive.isString()) { | |
param = jsonPrimitive.getAsString(); | |
} else if (jsonPrimitive.isNumber()) { | |
// valueObject = jsonPrimitive.getAsNumber(); | |
param = ctxt.deserialize(jsonPrimitive, | |
setterMethod.getGenericParameterTypes()[0]); | |
} | |
try { | |
setterMethod.invoke(entity, new Object[] { param }); | |
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { | |
LOGGER.info("Exception setter=" + setterMethod.getName() + " - " | |
+ setterMethod.getParameterTypes()[0] + "- valueObject.getClass:" | |
+ param.getClass(), e); | |
} | |
} | |
} else if (value.isJsonArray()) { | |
// list case | |
JsonArray jsonArray = (JsonArray) value; | |
List<?> params = new ArrayList<>(); | |
String initialPropertyName = propertyName; | |
if (initialPropertyName.startsWith("#")) { | |
initialPropertyName = initialPropertyName.substring(1); | |
} | |
Method setterMethod = getSetter(initialPropertyName, entity.getClass()); | |
if (setterMethod == null) { | |
LOGGER.debug("Setter not found for " + propertyName); | |
} else { | |
if (jsonArray.size() > 0) { | |
if (propertyName.startsWith("#")) { | |
// need load them through | |
MongoChildLoader<T> m = new MongoChildLoader<>(); | |
params = (List<?>) m.loadChildren(entity, jsonArray); | |
} else { | |
// inner object | |
params = (List<?>) ctxt.deserialize(jsonArray, | |
setterMethod.getGenericParameterTypes()[0]); | |
LOGGER.debug("jsonArray=" + jsonArray.toString() + " -> subObject=" + params); | |
} | |
} | |
try { | |
setterMethod.invoke(entity, new Object[] { params }); | |
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { | |
LOGGER.warn("", e); | |
} | |
} | |
} | |
} | |
LOGGER.debug(" * OUT * deserialize " + entity); | |
return entity; | |
} | |
private static Method getSetter(String propertyName, Class<?> clazz) { | |
String setterName = SET + propertyName; | |
for (Method method : clazz.getMethods()) { | |
if (setterName.equals(method.getName())) { | |
return method; | |
} | |
} | |
return null; | |
} | |
private final T create(JsonObject jsonObject) { | |
BigInteger type = jsonObject.get(RES_TYPE).getAsBigInteger(); | |
switch (type.intValue()) { | |
case ResourceType.AE: | |
return (T) new AeEntity(); | |
case ResourceType.CSE_BASE: | |
return (T) new CSEBaseEntity(); | |
case ResourceType.ACCESS_CONTROL_POLICY: | |
return (T) new AccessControlPolicyEntity(); | |
case ResourceType.FLEXCONTAINER: | |
return (T) new FlexContainerEntity(); | |
case ResourceType.CONTAINER: | |
return (T) new ContainerEntity(); | |
case ResourceType.CONTENT_INSTANCE: | |
return (T) new ContentInstanceEntity(); | |
case ResourceType.REMOTE_CSE: | |
return (T) new RemoteCSEEntity(); | |
case ResourceType.AE_ANNC: | |
return (T) new AeAnncEntity(); | |
case ResourceType.FLEXCONTAINER_ANNC: | |
return (T) new FlexContainerAnncEntity(); | |
case ResourceType.DYNAMIC_AUTHORIZATION_CONSULTATION: | |
return (T) new DynamicAuthorizationConsultationEntity(); | |
case ResourceType.NODE: | |
return (T) new NodeEntity(); | |
case ResourceType.NODE_ANNC: | |
return (T) new NodeAnncEntity(); | |
case ResourceType.MGMT_OBJ: | |
return (T) MgmtObjEntity.create(jsonObject.get(MGMT_DEF).getAsBigInteger()); | |
case ResourceType.MGMT_OBJ_ANNC: | |
return (T) MgmtObjAnncEntity.create(jsonObject.get(MGMT_DEF).getAsBigInteger()); | |
} | |
LOGGER.warn("Cannot create entity for " + type); | |
return null; | |
} | |
} |