All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.liferay.portal.json.jabsorb.serializer.LiferaySerializer Maven / Gradle / Ivy

There is a newer version: 7.4.3.112-ga112
Show newest version
/**
 * 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.petra.lang.ClassLoaderPool;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.Validator;

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());

				String contextName = ClassLoaderPool.getContextName(
					javaClass.getClassLoader());

				if (Validator.isNotNull(contextName)) {
					jsonObject.put("contextName", contextName);
				}
			}
			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 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;
					}

					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 {
			ClassLoader classLoader = null;

			if (jsonObject.has("contextName")) {
				String contextName = jsonObject.getString("contextName");

				classLoader = ClassLoaderPool.getClassLoader(contextName);

				if (classLoader == null) {
					if (_log.isWarnEnabled()) {
						_log.warn(
							StringBundler.concat(
								"Unable to get class loader for class ",
								javaClassName, " in context ", contextName));
					}
				}
			}

			if (classLoader != null) {
				Class.forName(javaClassName, true, classLoader);
			}
			else {
				Class.forName(javaClassName);
			}
		}
		catch (Exception e) {
			throw new UnmarshallException(
				"Unable to get class " + 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 {
			ClassLoader classLoader = null;

			if (jsonObject.has("contextName")) {
				String contextName = jsonObject.getString("contextName");

				classLoader = ClassLoaderPool.getClassLoader(contextName);

				if (classLoader == null) {
					if (_log.isWarnEnabled()) {
						_log.warn(
							StringBundler.concat(
								"Unable to get class loader for class ",
								javaClassName, " in context ", contextName));
					}
				}
			}

			if (classLoader != null) {
				javaClass = Class.forName(javaClassName, true, classLoader);
			}
			else {
				javaClass = Class.forName(javaClassName);
			}

			javaClassInstance = javaClass.newInstance();
		}
		catch (Exception e) {
			throw new UnmarshallException(
				"Unable to get class " + 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 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;
					}

					field.setAccessible(true);

					if (fieldName.startsWith("_")) {
						fieldName = fieldName.substring(1);
					}

					if (!serializableJSONObject.has(fieldName)) {
						continue;
					}

					Object value = null;

					try {
						value = ser.unmarshall(
							serializerState, field.getType(),
							serializableJSONObject.get(fieldName));
					}
					catch (Exception e) {
						if (_log.isDebugEnabled()) {
							_log.debug(e, 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);

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy