/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.json.jabsorb.serializer; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import java.io.Serializable; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.jabsorb.JSONSerializer; import org.jabsorb.serializer.AbstractSerializer; import org.jabsorb.serializer.MarshallException; import org.jabsorb.serializer.ObjectMatch; import org.jabsorb.serializer.SerializerState; import org.jabsorb.serializer.UnmarshallException; import org.json.JSONObject; /** * @author Raymond Augé */ public class LiferaySerializer extends AbstractSerializer { @Override public boolean canSerialize( @SuppressWarnings("rawtypes") Class clazz, @SuppressWarnings("rawtypes") Class jsonClass) { Constructor<?> constructor = null; try { constructor = clazz.getConstructor(); } catch (Exception e) { } if (Serializable.class.isAssignableFrom(clazz) && ((jsonClass == null) || (jsonClass == JSONObject.class)) && (constructor != null)) { return true; } return false; } @Override public Class<?>[] getJSONClasses() { return _JSON_CLASSES; } @Override public Class<?>[] getSerializableClasses() { return _SERIALIZABLE_CLASSES; } @Override public Object marshall( SerializerState serializerState, Object parentObject, Object object) throws MarshallException { JSONObject jsonObject = new JSONObject(); Class<?> javaClass = object.getClass(); if (ser.getMarshallClassHints()) { try { jsonObject.put("javaClass", javaClass.getName()); } catch (Exception e) { throw new MarshallException("Unable to put javaClass", e); } } JSONObject serializableJSONObject = new JSONObject(); try { jsonObject.put("serializable", serializableJSONObject); serializerState.push( object, serializableJSONObject, "serializable"); } catch (Exception e) { throw new MarshallException("Unable to put serializable", e); } String fieldName = null; try { Set<String> processedFieldNames = new HashSet<>(); while (javaClass != null) { Field[] declaredFields = javaClass.getDeclaredFields(); for (Field field : declaredFields) { fieldName = field.getName(); // Avoid processing overridden fields of super classes if (processedFieldNames.contains(fieldName)) { continue; } processedFieldNames.add(fieldName); int modifiers = field.getModifiers(); // Only marshall fields that are not static or transient if (((modifiers & Modifier.STATIC) == Modifier.STATIC) || ((modifiers & Modifier.TRANSIENT) == Modifier.TRANSIENT)) { continue; } if (!field.isAccessible()) { field.setAccessible(true); } if (fieldName.startsWith("_")) { fieldName = fieldName.substring(1); } Object fieldObject = ser.marshall( serializerState, serializableJSONObject, field.get(object), fieldName); // Omit the object entirely if it is a circular reference or // duplicate. It will be regenerated in the fixups phase. if (JSONSerializer.CIRC_REF_OR_DUPLICATE != fieldObject) { serializableJSONObject.put(fieldName, fieldObject); } else if (!serializableJSONObject.has(fieldName)) { serializableJSONObject.put( fieldName, field.get(object)); } } javaClass = javaClass.getSuperclass(); } } catch (Exception e) { throw new MarshallException( "Unable to match field " + fieldName, e); } finally { serializerState.pop(); } return jsonObject; } @Override public ObjectMatch tryUnmarshall( SerializerState serializerState, @SuppressWarnings("rawtypes") Class clazz, Object object) throws UnmarshallException { JSONObject jsonObject = (JSONObject)object; String javaClassName = null; try { javaClassName = jsonObject.getString("javaClass"); } catch (Exception e) { throw new UnmarshallException("Unable to get javaClass", e); } if (javaClassName == null) { throw new UnmarshallException("javaClass is undefined"); } try { Class.forName(javaClassName); } catch (Exception e) { throw new UnmarshallException( "Unable to load javaClass " + javaClassName, e); } JSONObject serializableJSONObject = null; try { serializableJSONObject = jsonObject.getJSONObject("serializable"); } catch (Exception e) { throw new UnmarshallException("Unable to get serializable", e); } if (serializableJSONObject == null) { throw new UnmarshallException("serializable is undefined"); } ObjectMatch objectMatch = new ObjectMatch(-1); serializerState.setSerialized(object, objectMatch); String fieldName = null; try { Iterator<?> iterator = serializableJSONObject.keys(); while (iterator.hasNext()) { fieldName = (String)iterator.next(); ObjectMatch fieldObjectMatch = ser.tryUnmarshall( serializerState, null, serializableJSONObject.get(fieldName)); ObjectMatch maxFieldObjectMatch = fieldObjectMatch.max( objectMatch); objectMatch.setMismatch(maxFieldObjectMatch.getMismatch()); } } catch (Exception e) { throw new UnmarshallException( "Unable to match field " + fieldName, e); } return objectMatch; } @Override public Object unmarshall( SerializerState serializerState, @SuppressWarnings("rawtypes") Class clazz, Object object) throws UnmarshallException { JSONObject jsonObject = (JSONObject)object; String javaClassName = null; try { javaClassName = jsonObject.getString("javaClass"); } catch (Exception e) { throw new UnmarshallException("Unable to get javaClass", e); } if (javaClassName == null) { throw new UnmarshallException("javaClass is undefined"); } Class<?> javaClass = null; Object javaClassInstance = null; try { javaClass = Class.forName(javaClassName); javaClassInstance = javaClass.newInstance(); } catch (Exception e) { throw new UnmarshallException( "Unable to load javaClass " + javaClassName, e); } JSONObject serializableJSONObject = null; try { serializableJSONObject = jsonObject.getJSONObject("serializable"); } catch (Exception e) { throw new UnmarshallException("Unable to get serializable", e); } if (serializableJSONObject == null) { throw new UnmarshallException("serializable is undefined"); } serializerState.setSerialized(object, javaClassInstance); String fieldName = null; try { Set<String> processedFieldNames = new HashSet<>(); while (javaClass != null) { Field[] fields = javaClass.getDeclaredFields(); for (Field field : fields) { fieldName = field.getName(); // Avoid processing overridden fields of super classes if (processedFieldNames.contains(fieldName)) { continue; } processedFieldNames.add(fieldName); int modifiers = field.getModifiers(); // Only unmarshall fields that are not static or transient if (((modifiers & Modifier.STATIC) == Modifier.STATIC) || ((modifiers & Modifier.TRANSIENT) == Modifier.TRANSIENT)) { continue; } if (!field.isAccessible()) { field.setAccessible(true); } if (fieldName.startsWith("_")) { fieldName = fieldName.substring(1); } Object value = null; if (!serializableJSONObject.has(fieldName)) { continue; } try { value = ser.unmarshall( serializerState, field.getType(), serializableJSONObject.get(fieldName)); } catch (Exception e) { } if (value != null) { try { field.set(javaClassInstance, value); } catch (Exception e) { _log.error(e, e); } } } javaClass = javaClass.getSuperclass(); } } catch (Exception e) { throw new UnmarshallException( "Unable to match field " + fieldName, e); } return javaClassInstance; } private static final Class<?>[] _JSON_CLASSES = {JSONObject.class}; private static final Class<?>[] _SERIALIZABLE_CLASSES = {Serializable.class}; private static final Log _log = LogFactoryUtil.getLog( LiferaySerializer.class); }