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

com.uber.hoodie.common.util.SerializationUtils Maven / Gradle / Ivy

There is a newer version: 0.4.7
Show newest version
/*
 *  Copyright (c) 2018 Uber Technologies, Inc. ([email protected])
 *
 *  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 com.uber.hoodie.common.util;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.FieldSerializer;
import com.esotericsoftware.reflectasm.ConstructorAccess;
import com.uber.hoodie.exception.HoodieSerializationException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import org.objenesis.instantiator.ObjectInstantiator;


/**
 * {@link SerializationUtils} class internally uses {@link Kryo} serializer for serializing /
 * deserializing objects.
 */
public class SerializationUtils {

  // Caching kryo serializer to avoid creating kryo instance for every serde operation
  private static final ThreadLocal serializerRef =
      ThreadLocal.withInitial(() -> new KryoSerializerInstance());

  // Serialize
  //-----------------------------------------------------------------------

  /**
   * 

Serializes an {@code Object} to a byte array for storage/serialization.

* * @param obj the object to serialize to bytes * @return a byte[] with the converted Serializable * @throws IOException if the serialization fails */ public static byte[] serialize(final Object obj) throws IOException { return serializerRef.get().serialize(obj); } // Deserialize //----------------------------------------------------------------------- /** *

Deserializes a single {@code Object} from an array of bytes.

* *

If the call site incorrectly types the return value, a {@link ClassCastException} is thrown * from the call site. Without Generics in this declaration, the call site must type cast and can * cause the same ClassCastException. Note that in both cases, the ClassCastException is in the * call site, not in this method.

* * @param the object type to be deserialized * @param objectData the serialized object, must not be null * @return the deserialized object * @throws IllegalArgumentException if {@code objectData} is {@code null} * @throws HoodieSerializationException (runtime) if the serialization fails */ public static T deserialize(final byte[] objectData) { if (objectData == null) { throw new IllegalArgumentException("The byte[] must not be null"); } return (T) serializerRef.get().deserialize(objectData); } private static class KryoSerializerInstance implements Serializable { public static final int KRYO_SERIALIZER_INITIAL_BUFFER_SIZE = 1048576; private final Kryo kryo; // Caching ByteArrayOutputStream to avoid recreating it for every operation private final ByteArrayOutputStream baos; KryoSerializerInstance() { KryoInstantiator kryoInstantiator = new KryoInstantiator(); kryo = kryoInstantiator.newKryo(); baos = new ByteArrayOutputStream(KRYO_SERIALIZER_INITIAL_BUFFER_SIZE); kryo.setRegistrationRequired(false); } byte[] serialize(Object obj) throws IOException { kryo.reset(); baos.reset(); Output output = new Output(baos); this.kryo.writeClassAndObject(output, obj); output.close(); return baos.toByteArray(); } Object deserialize(byte[] objectData) { return this.kryo.readClassAndObject(new Input(objectData)); } } /** * This class has a no-arg constructor, suitable for use with reflection instantiation. * For Details checkout com.twitter.chill.KryoBase. */ private static class KryoInstantiator implements Serializable { public Kryo newKryo() { Kryo kryo = new KryoBase(); // ensure that kryo doesn't fail if classes are not registered with kryo. kryo.setRegistrationRequired(false); // This would be used for object initialization if nothing else works out. kryo.setInstantiatorStrategy(new org.objenesis.strategy.StdInstantiatorStrategy()); // Handle cases where we may have an odd classloader setup like with libjars // for hadoop kryo.setClassLoader(Thread.currentThread().getContextClassLoader()); return kryo; } private static class KryoBase extends Kryo { @Override protected Serializer newDefaultSerializer(Class type) { final Serializer serializer = super.newDefaultSerializer(type); if (serializer instanceof FieldSerializer) { final FieldSerializer fieldSerializer = (FieldSerializer) serializer; fieldSerializer.setIgnoreSyntheticFields(true); } return serializer; } @Override protected ObjectInstantiator newInstantiator(Class type) { return () -> { // First try reflectasm - it is fastest way to instantiate an object. try { final ConstructorAccess access = ConstructorAccess.get(type); return access.newInstance(); } catch (Throwable t) { // ignore this exception. We may want to try other way. } // fall back to java based instantiation. try { final Constructor constructor = type.getConstructor(); constructor.setAccessible(true); return constructor.newInstance(); } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) { // ignore this exception. we will fall back to default instantiation strategy. } return super.getInstantiatorStrategy().newInstantiatorOf(type).newInstance(); }; } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy