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

com.github.ddth.commons.utils.SerializationUtils Maven / Gradle / Ivy

There is a newer version: 1.1.0
Show newest version
package com.github.ddth.commons.utils;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.nustaq.serialization.FSTConfiguration;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.util.Pool;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.NullNode;
import com.github.ddth.commons.serialization.DeserializationException;
import com.github.ddth.commons.serialization.ISerializationSupport;
import com.github.ddth.commons.serialization.SerializationException;

/**
 * Serialization helper class.
 * 
 * 
    *
  • JSON serialization: use {@code com.fasterxml.jackson} library.
  • *
  • Binary serialization: 3 choices of API *
      *
    • {@code jboss-serialization} library (deprecated since v0.6.0!), or
    • *
    • {@code Kryo} library or
    • *
    • {@code FST} library
    • *
    *
  • *
* * @author Thanh Nguyen * @since 0.2.0 */ public class SerializationUtils { /*----------------------------------------------------------------------*/ /** * Serialize an object to byte array. * *

* If the target object implements {@link ISerializationSupport}, this * method calls its {@link ISerializationSupport#toBytes()} method; * otherwise FST library is used to serialize the object. *

* * @param obj * @return * @deprecated since 0.9.2 with no replacement, use {@link #toByteArrayFst(Object)} or * {@link #toByteArrayKryo(Object)} */ public static byte[] toByteArray(Object obj) { return toByteArray(obj, null); } /** * Serialize an object to byte array, with a custom class loader. * *

* If the target object implements {@link ISerializationSupport}, this * method calls its {@link ISerializationSupport#toBytes()} method; * otherwise FST library is used to serialize the object. *

* * @param obj * @param classLoader * @return * @deprecated since 0.9.2 with no replacement, use {@link #toByteArrayFst(Object, ClassLoader)} * or {@link #toByteArrayKryo(Object, ClassLoader)} */ public static byte[] toByteArray(Object obj, ClassLoader classLoader) { if (obj instanceof ISerializationSupport) { ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); if (classLoader != null) { Thread.currentThread().setContextClassLoader(classLoader); } try { return ((ISerializationSupport) obj).toBytes(); } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); } } else { return toByteArrayFst(obj, classLoader); } } /** * Deserialize a byte array back to an object. * *

* If the target class implements {@link ISerializationSupport}, this method * calls its {@link ISerializationSupport#toBytes()} method; otherwise FST * library is used to serialize the object. *

* * @param data * @param clazz * @return * @deprecated since 0.9.2 with no replacement, use {@link #fromByteArrayFst(byte[], Class)} or * {@link #fromByteArrayKryo(byte[], Class)} */ public static T fromByteArray(byte[] data, Class clazz) { return fromByteArray(data, clazz, null); } /** * Deserialize a byte array back to an object, with custom class loader. * *

* If the target class implements {@link ISerializationSupport}, this method * calls its {@link ISerializationSupport#toBytes()} method; otherwise FST * library is used to serialize the object. *

* * @param data * @param clazz * @param classLoader * @return * @deprecated since 0.9.2 with no replacement, use * {@link #fromByteArrayFst(byte[], Class, ClassLoader)} or * {@link #fromByteArrayKryo(byte[], Class, ClassLoader)} */ public static T fromByteArray(byte[] data, Class clazz, ClassLoader classLoader) { if (data == null) { return null; } if (ReflectionUtils.hasInterface(clazz, ISerializationSupport.class)) { ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); if (classLoader != null) { Thread.currentThread().setContextClassLoader(classLoader); } try { Constructor constructor = clazz.getDeclaredConstructor(); constructor.setAccessible(true); T obj = constructor.newInstance(); ((ISerializationSupport) obj).fromBytes(data); return obj; } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) { throw new DeserializationException(e); } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); } } return SerializationUtils.fromByteArrayFst(data, clazz, classLoader); } /*----------------------------------------------------------------------*/ private static Pool kryoPool; private static Pool kryoOutputPool; private static Pool kryoInputPool; static { int numCpuCores = Runtime.getRuntime().availableProcessors(); kryoPool = new Pool(true /* thread-safe */, false/* soft-ref */, numCpuCores) { protected Kryo create() { Kryo kryo = new Kryo(); kryo.setRegistrationRequired(false); kryo.setWarnUnregisteredClasses(false); // (optional) configure the Kryo instance return kryo; } }; kryoOutputPool = new Pool(true/* thread-safe */, false/* soft-ref */, numCpuCores) { protected Output create() { return new Output(1024, -1); } }; kryoInputPool = new Pool(true/* thread-safe */, false/* soft-ref */, numCpuCores) { protected Input create() { return new Input(1024); } }; } /** * Serialize an object to byte array. * *

* This method uses Kryo lib. *

* * @param obj * @return */ public static byte[] toByteArrayKryo(Object obj) { return toByteArrayKryo(obj, null); } /** * Serialize an object to byte array, with a custom class loader. * *

* This method uses Kryo lib. *

* * @param obj * @param classLoader * @return */ public static byte[] toByteArrayKryo(Object obj, ClassLoader classLoader) { if (obj == null) { return null; } Kryo kryo = kryoPool.obtain(); try { ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); if (classLoader != null) { Thread.currentThread().setContextClassLoader(classLoader); } try { Output output = kryoOutputPool.obtain(); try { kryo.setClassLoader(classLoader != null ? classLoader : oldClassLoader); // kryo.writeObject(output, obj); kryo.writeClassAndObject(output, obj); output.close(); return output.toBytes(); } catch (Exception e) { throw e instanceof SerializationException ? (SerializationException) e : new SerializationException(e); } finally { kryoOutputPool.free(output); } } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); } } finally { kryoPool.free(kryo); } } /** * Deserialize a byte array back to an object. * *

* This method uses Kryo lib. *

* * @param data * @return */ public static Object fromByteArrayKryo(byte[] data) { return fromByteArrayKryo(data, Object.class, null); } /** * Deserialize a byte array back to an object, with custom class loader. * *

* This method uses Kryo lib. *

* * @param data * @param classLoader * @return */ public static Object fromByteArrayKryo(byte[] data, ClassLoader classLoader) { return fromByteArrayKryo(data, Object.class, classLoader); } /** * Deserialize a byte array back to an object. * *

* This method uses Kryo lib. *

* * @param data * @param clazz * @return */ public static T fromByteArrayKryo(byte[] data, Class clazz) { return fromByteArrayKryo(data, clazz, null); } /** * Deserialize a byte array back to an object, with custom class loader. * *

* This method uses Kryo lib. *

* * @param data * @param clazz * @param classLoader * @return */ @SuppressWarnings("unchecked") public static T fromByteArrayKryo(byte[] data, Class clazz, ClassLoader classLoader) { if (data == null) { return null; } Kryo kryo = kryoPool.obtain(); try { ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); if (classLoader != null) { Thread.currentThread().setContextClassLoader(classLoader); } try { Input input = kryoInputPool.obtain(); try { kryo.setClassLoader(classLoader != null ? classLoader : oldClassLoader); input.setInputStream(new ByteArrayInputStream(data)); Object obj = kryo.readClassAndObject(input); input.close(); return obj != null && clazz.isAssignableFrom(obj.getClass()) ? (T) obj : null; } finally { kryoInputPool.free(input); } } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); } } finally { kryoPool.free(kryo); } } /*----------------------------------------------------------------------*/ private final static ObjectPool poolMapper = new GenericObjectPool( new BasePooledObjectFactory() { @Override public ObjectMapper create() throws Exception { return new ObjectMapper(); } @Override public PooledObject wrap(ObjectMapper objMapper) { return new DefaultPooledObject(objMapper); } }); static { GenericObjectPool pool = (GenericObjectPool) poolMapper; pool.setMaxIdle(1); pool.setMaxTotal(100); pool.setMaxWaitMillis(5000); pool.setBlockWhenExhausted(true); } /** * Serialize an object to JSON string. * * @param obj * @return */ public static String toJsonString(Object obj) { return toJsonString(obj, null); } /** * Serialize an object to JSON string, with a custom class loader. * * @param obj * @param classLoader * @return */ public static String toJsonString(Object obj, ClassLoader classLoader) { if (obj == null) { return "null"; } ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); if (classLoader != null) { Thread.currentThread().setContextClassLoader(classLoader); } try { ObjectMapper mapper = poolMapper.borrowObject(); if (mapper != null) { try { return mapper.writeValueAsString(obj); } finally { poolMapper.returnObject(mapper); } } throw new SerializationException("No ObjectMapper instance avaialble!"); } catch (Exception e) { throw e instanceof SerializationException ? (SerializationException) e : new SerializationException(e); } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); } } /** * Serialize an object to {@link JsonNode}. * * @param obj * @return * @since 0.6.2 */ public static JsonNode toJson(Object obj) { return toJson(obj, null); } /** * Serialize an object to {@link JsonNode}, with a custom class loader. * * @param obj * @param classLoader * @return * @since 0.6.2 */ public static JsonNode toJson(Object obj, ClassLoader classLoader) { ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); if (classLoader != null) { Thread.currentThread().setContextClassLoader(classLoader); } try { if (obj == null) { return NullNode.instance; } ObjectMapper mapper = poolMapper.borrowObject(); if (mapper != null) { try { return mapper.valueToTree(obj); } finally { poolMapper.returnObject(mapper); } } throw new SerializationException("No ObjectMapper instance avaialble!"); } catch (Exception e) { throw e instanceof SerializationException ? (SerializationException) e : new SerializationException(e); } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); } } /** * Read a JSON string and parse to {@link JsonNode} instance. * * @param source * @return * @since 0.6.2 */ public static JsonNode readJson(String source) { return readJson(source, null); } /** * Read a JSON string and parse to {@link JsonNode} instance, with a custom class loader. * * @param source * @param classLoader * @return * @since 0.6.2 */ public static JsonNode readJson(String source, ClassLoader classLoader) { ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); if (classLoader != null) { Thread.currentThread().setContextClassLoader(classLoader); } try { if (StringUtils.isBlank(source)) { return NullNode.instance; } ObjectMapper mapper = poolMapper.borrowObject(); if (mapper != null) { try { return mapper.readTree(source); } finally { poolMapper.returnObject(mapper); } } throw new SerializationException("No ObjectMapper instance avaialble!"); } catch (Exception e) { throw e instanceof SerializationException ? (SerializationException) e : new SerializationException(e); } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); } } /** * Read a JSON string and parse to {@link JsonNode} instance. * * @param source * @return * @since 0.6.2 */ public static JsonNode readJson(byte[] source) { return readJson(source, null); } /** * Read a JSON string and parse to {@link JsonNode} instance, with a custom class loader. * * @param source * @param classLoader * @return * @since 0.6.2 */ public static JsonNode readJson(byte[] source, ClassLoader classLoader) { ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); if (classLoader != null) { Thread.currentThread().setContextClassLoader(classLoader); } try { if (source == null || source.length == 0) { return NullNode.instance; } ObjectMapper mapper = poolMapper.borrowObject(); if (mapper != null) { try { return mapper.readTree(source); } finally { poolMapper.returnObject(mapper); } } throw new SerializationException("No ObjectMapper instance avaialble!"); } catch (Exception e) { throw e instanceof SerializationException ? (SerializationException) e : new SerializationException(e); } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); } } /** * Read a JSON string and parse to {@link JsonNode} instance. * * @param source * @return * @since 0.6.2 */ public static JsonNode readJson(InputStream source) { return readJson(source, null); } /** * Read a JSON string and parse to {@link JsonNode} instance, with a custom class loader. * * @param source * @param classLoader * @return * @since 0.6.2 */ public static JsonNode readJson(InputStream source, ClassLoader classLoader) { ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); if (classLoader != null) { Thread.currentThread().setContextClassLoader(classLoader); } try { if (source == null) { return NullNode.instance; } ObjectMapper mapper = poolMapper.borrowObject(); if (mapper != null) { try { return mapper.readTree(source); } finally { poolMapper.returnObject(mapper); } } throw new SerializationException("No ObjectMapper instance avaialble!"); } catch (Exception e) { throw e instanceof SerializationException ? (SerializationException) e : new SerializationException(e); } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); } } /** * Read a JSON string and parse to {@link JsonNode} instance. * * @param source * @return * @since 0.6.2 */ public static JsonNode readJson(Reader source) { return readJson(source, null); } /** * Read a JSON string and parse to {@link JsonNode} instance, with a custom class loader. * * @param source * @param classLoader * @return * @since 0.6.2 */ public static JsonNode readJson(Reader source, ClassLoader classLoader) { ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); if (classLoader != null) { Thread.currentThread().setContextClassLoader(classLoader); } try { if (source == null) { return NullNode.instance; } ObjectMapper mapper = poolMapper.borrowObject(); if (mapper != null) { try { return mapper.readTree(source); } finally { poolMapper.returnObject(mapper); } } throw new SerializationException("No ObjectMapper instance avaialble!"); } catch (Exception e) { throw e instanceof SerializationException ? (SerializationException) e : new SerializationException(e); } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); } } /** * Deserialize a JSON string. * * @param jsonString * @return */ public static Object fromJsonString(String jsonString) { return fromJsonString(jsonString, Object.class, null); } /** * Deserialize a JSON string, with custom class loader. * * @param jsonString * @param classLoader * @return */ public static Object fromJsonString(String jsonString, ClassLoader classLoader) { return fromJsonString(jsonString, Object.class, classLoader); } /** * Deserialize a JSON string. * * @param jsonString * @param clazz * @return */ public static T fromJsonString(String jsonString, Class clazz) { return fromJsonString(jsonString, clazz, null); } /** * Deserialize a JSON string, with custom class loader. * * @param jsonString * @param clazz * @return */ public static T fromJsonString(String jsonString, Class clazz, ClassLoader classLoader) { if (jsonString == null) { return null; } ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); if (classLoader != null) { Thread.currentThread().setContextClassLoader(classLoader); } try { ObjectMapper mapper = poolMapper.borrowObject(); if (mapper != null) { try { return mapper.readValue(jsonString, clazz); } finally { poolMapper.returnObject(mapper); } } throw new DeserializationException("No ObjectMapper instance avaialble!"); } catch (Exception e) { throw e instanceof DeserializationException ? (DeserializationException) e : new DeserializationException(e); } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); } } /** * Deserialize a {@link JsonNode}. * * @param json * @return * @since 0.6.2 */ public static Object fromJson(JsonNode json) { return fromJson(json, Object.class, null); } /** * Deserialize a {@link JsonNode}, with custom class loader. * * @param json * @param classLoader * @return * @since 0.6.2 */ public static Object fromJson(JsonNode json, ClassLoader classLoader) { return fromJson(json, Object.class, classLoader); } /** * Deserialize a {@link JsonNode}. * * @param json * @param clazz * @return * @since 0.6.2 */ public static T fromJson(JsonNode json, Class clazz) { return fromJson(json, clazz, null); } /** * Deserialize a {@link JsonNode}, with custom class loader. * * @param json * @param clazz * @return * @since 0.6.2 */ public static T fromJson(JsonNode json, Class clazz, ClassLoader classLoader) { if (json == null) { return null; } ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); if (classLoader != null) { Thread.currentThread().setContextClassLoader(classLoader); } try { ObjectMapper mapper = poolMapper.borrowObject(); if (mapper != null) { try { return mapper.readValue(json.toString(), clazz); } finally { poolMapper.returnObject(mapper); } } throw new DeserializationException("No ObjectMapper instance avaialble!"); } catch (Exception e) { throw e instanceof DeserializationException ? (DeserializationException) e : new DeserializationException(e); } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); } } /*----------------------------------------------------------------------*/ private static ThreadLocal fstConf = new ThreadLocal() { public FSTConfiguration initialValue() { FSTConfiguration conf = FSTConfiguration.createDefaultConfiguration(); conf.setForceSerializable(true); return conf; } }; /** * Serialize an object to byte array. * *

* This method uses FST lib. *

* * @param obj * @return * @since 0.6.0 */ public static byte[] toByteArrayFst(Object obj) { return toByteArrayFst(obj, null); } /** * Serialize an object to byte array, with a custom class loader. * *

* This method uses FST lib. *

* * @param obj * @param classLoader * @return * @since 0.6.0 */ public static byte[] toByteArrayFst(final Object obj, final ClassLoader classLoader) { if (obj == null) { return null; } ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); if (classLoader != null) { Thread.currentThread().setContextClassLoader(classLoader); } try { FSTConfiguration conf = fstConf.get(); conf.setClassLoader(classLoader != null ? classLoader : oldClassLoader); return conf.asByteArray(obj); } catch (Exception e) { throw e instanceof SerializationException ? (SerializationException) e : new SerializationException(e); } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); } } /** * Deserialize a byte array back to an object. * *

* This method uses FST lib. *

* * @param data * @return * @since 0.6.0 */ public static Object fromByteArrayFst(byte[] data) { return fromByteArrayFst(data, Object.class, null); } /** * Deserialize a byte array back to an object, with custom class loader. * *

* This method uses FST lib. *

* * @param data * @param classLoader * @return * @since 0.6.0 */ public static Object fromByteArrayFst(byte[] data, ClassLoader classLoader) { return fromByteArrayFst(data, Object.class, classLoader); } /** * Deserialize a byte array back to an object. * *

* This method uses FST lib. *

* * @param data * @param clazz * @return * @since 0.6.0 */ public static T fromByteArrayFst(byte[] data, Class clazz) { return fromByteArrayFst(data, clazz, null); } /** * Deserialize a byte array back to an object, with custom class loader. * *

* This method uses FST lib. *

* * @param data * @param clazz * @param classLoader * @return * @since 0.6.0 */ @SuppressWarnings("unchecked") public static T fromByteArrayFst(final byte[] data, final Class clazz, final ClassLoader classLoader) { if (data == null) { return null; } ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); if (classLoader != null) { Thread.currentThread().setContextClassLoader(classLoader); } try { FSTConfiguration conf = fstConf.get(); conf.setClassLoader(classLoader != null ? classLoader : oldClassLoader); Object result = conf.asObject(data); if (result != null && clazz.isAssignableFrom(result.getClass())) { return (T) result; } else { return null; } } catch (Exception e) { throw e instanceof DeserializationException ? (DeserializationException) e : new DeserializationException(e); } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy