package de.javakaffee.kryoserializers.guava;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.google.common.collect.ImmutableSortedSet;
import java.util.Comparator;

/**
 * A kryo {@link Serializer} for guava-libraries {@link ImmutableSortedSet}.
 */
public class ImmutableSortedSetSerializer extends Serializer<ImmutableSortedSet<Object>> {

  private static final boolean DOES_NOT_ACCEPT_NULL = false;
  private static final boolean IMMUTABLE = true;

  public ImmutableSortedSetSerializer() {
    super(DOES_NOT_ACCEPT_NULL, IMMUTABLE);
  }

  @Override
  public void write(Kryo kryo, Output output, ImmutableSortedSet<Object> object) {
    kryo.writeClassAndObject(output, object.comparator());
    output.writeInt(object.size(), true);
    for (Object elm : object) {
      kryo.writeClassAndObject(output, elm);
    }
  }

  @Override
  public ImmutableSortedSet<Object> read(Kryo kryo, Input input, Class<? extends ImmutableSortedSet<Object>> type) {
    @SuppressWarnings ("unchecked")
    ImmutableSortedSet.Builder<Object> builder = ImmutableSortedSet.orderedBy((Comparator<Object>)kryo.readClassAndObject (input));
    final int size = input.readInt(true);
    for (int i = 0; i < size; ++i) {
      builder.add(kryo.readClassAndObject(input));
    }
    return builder.build();
  }

  /**
   * Creates a new {@link ImmutableSortedSetSerializer} and registers its serializer
   * for the several ImmutableSortedSet related classes.
   *
   * @param kryo the {@link Kryo} instance to set the serializer on
   */
  public static void registerSerializers(final Kryo kryo) {

    // ImmutableSortedSet (abstract class)
    //  +- EmptyImmutableSortedSet
    //  +- RegularImmutableSortedSet
    //  +- DescendingImmutableSortedSet

    final ImmutableSortedSetSerializer serializer = new ImmutableSortedSetSerializer();

    kryo.register(ImmutableSortedSet.class, serializer);
    kryo.register(ImmutableSortedSet.of().getClass(), serializer);
    kryo.register(ImmutableSortedSet.of("").getClass(), serializer);
    kryo.register(ImmutableSortedSet.of().descendingSet ().getClass(), serializer);
  }
}


package de.javakaffee.kryoserializers.guava;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Table;
import com.google.common.collect.TreeBasedTable;

import java.util.Comparator;
import java.util.Set;

/**
 * A kryo {@link Serializer} for guava-libraries {@link TreeBasedTable}.
 */
public class TreeBasedTableSerializer<R extends Comparable, C extends Comparable, V> extends TableSerializerBase<R, C, V, TreeBasedTable<R, C, V>> {

    private static final boolean HANDLES_NULL = false;
    private static final boolean IMMUTABLE = false;

    public TreeBasedTableSerializer() {
        super(HANDLES_NULL, IMMUTABLE);
    }

    @Override
    public void write(Kryo kryo, Output output, TreeBasedTable<R, C, V> table) {
        kryo.writeClassAndObject(output, table.rowComparator());
        kryo.writeClassAndObject(output, table.columnComparator());
        super.writeTable(kryo, output, table);
    }

    @Override
    public TreeBasedTable<R, C, V> read(Kryo kryo, Input input, Class<? extends TreeBasedTable<R, C, V>> type) {
        Comparator<? super Comparable> rowComparator = (Comparator<? super Comparable>) kryo.readClassAndObject(input);
        Comparator<? super Comparable> columnComparator = (Comparator<? super Comparable>) kryo.readClassAndObject(input);
        TreeBasedTable<R, C, V> table = TreeBasedTable.create(rowComparator, columnComparator);
        super.readTable(kryo, input, table);
        return table;
    }

    @Override
    public TreeBasedTable<R, C, V> copy(final Kryo kryo, final TreeBasedTable<R, C, V> original) {
        return TreeBasedTable.create(original);
    }

    /**
     * Creates a new {@link TreeBasedTableSerializer} and registers its serializer.
     *
     * @param kryo the {@link Kryo} instance to set the serializer on
     */
    public static void registerSerializers(final Kryo kryo) {
        final TreeBasedTableSerializer serializer = new TreeBasedTableSerializer();
        kryo.register(TreeBasedTable.class, serializer);
    }
}


/*
 * Copyright 2010 Martin Grotzke
 *
 * 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 de.javakaffee.kryoserializers;

import java.lang.reflect.Constructor;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import sun.reflect.ReflectionFactory;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.serializers.FieldSerializer;

/**
 * A {@link Kryo} specialization that uses sun's {@link ReflectionFactory} to create
 * new instance for classes without a default constructor.
 *
 * @author Martin Grotzke
 */
@SuppressWarnings("restriction")
public class KryoReflectionFactorySupport extends Kryo {

    private static final ReflectionFactory REFLECTION_FACTORY = ReflectionFactory.getReflectionFactory();
    private static final Object[] INITARGS = new Object[0];

    private static final Map<Class<?>, Constructor<?>> _constructors = new ConcurrentHashMap<Class<?>, Constructor<?>>();

    @Override
    public Serializer<?> getDefaultSerializer(@SuppressWarnings("rawtypes") final Class type) {
        final Serializer<?> result = super.getDefaultSerializer(type);
        if(result instanceof FieldSerializer && ((FieldSerializer<?>) result).getFieldSerializerConfig().getIgnoreSyntheticFields()) {
            // don't ignore synthetic fields so that inner classes work (see KryoTest.testInnerClass)
            FieldSerializer<?> fieldSerializer = (FieldSerializer<?>) result;
            fieldSerializer.getFieldSerializerConfig().setIgnoreSyntheticFields(false);
            fieldSerializer.updateFields();
        }
        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings( "unchecked" )
    public <T> T newInstance( final Class<T> type ) {
        if (type == null) { throw new IllegalArgumentException("type cannot be null."); }
        Constructor<?> constructor = _constructors.get( type );
        if ( constructor == null ) {
            constructor = getNoArgsConstructor( type );
            if ( constructor == null ) {
                constructor = newConstructorForSerialization( type );
            }
            _constructors.put( type, constructor );
        }
        return (T) newInstanceFrom( constructor );
    }

    private static Object newInstanceFrom( final Constructor<?> constructor ) {
        try {
            return constructor.newInstance( INITARGS );
        } catch ( final Exception e ) {
            throw new RuntimeException( e );
        }
    }

    @SuppressWarnings( "unchecked" )
    public static <T> T newInstanceFromReflectionFactory( final Class<T> type ) {
        Constructor<?> constructor = _constructors.get( type );
        if ( constructor == null ) {
            constructor = newConstructorForSerialization( type );
            _constructors.put( type, constructor );
        }
        return (T) newInstanceFrom( constructor );
    }

    private static <T> Constructor<?> newConstructorForSerialization( final Class<T> type ) {
        try {
            final Constructor<?> constructor = REFLECTION_FACTORY.newConstructorForSerialization( type, Object.class.getDeclaredConstructor( new Class[0] ) );
            constructor.setAccessible( true );
            return constructor;
        } catch ( final Exception e ) {
            throw new RuntimeException( e );
        }
    }

    private static Constructor<?> getNoArgsConstructor( final Class<?> type ) {
        final Constructor<?>[] constructors = type.getConstructors();
        for ( final Constructor<?> constructor : constructors ) {
            if ( constructor.getParameterTypes().length == 0 ) {
                constructor.setAccessible( true );
                return constructor;
            }
        }
        return null;
    }

}


package de.javakaffee.kryoserializers.guava;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Sets;

import java.lang.reflect.Field;
import java.util.NavigableSet;
import java.util.TreeSet;

/**
 * A kryo {@link Serializer} for guava-libraries {@link ImmutableSortedSet}.
 */
public class UnmodifiableNavigableSetSerializer extends Serializer<NavigableSet<?>> {

    Field delegate;

    public UnmodifiableNavigableSetSerializer() {
        // Do not allow nulls
        super(false);
        try {
            Class<?> clazz = Class.forName(Sets.class.getCanonicalName() + "$UnmodifiableNavigableSet");
            delegate = clazz.getDeclaredField("delegate");
            delegate.setAccessible(true);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException("Issues reflectively writing UnmodifiableNavigableSet", e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("Issues reflectively writing UnmodifiableNavigableSet", e);
        } catch (SecurityException e) {
            throw new RuntimeException("Issues reflectively writing UnmodifiableNavigableSet", e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException("Issues reflectively writing UnmodifiableNavigableSet", e);
        }
    }

    @VisibleForTesting
    protected Object getDelegateFromUnmodifiableNavigableSet(NavigableSet<?> object) {
        try {
            return delegate.get(object);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException("Issues reflectively writing UnmodifiableNavigableSet", e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Issues reflectively writing UnmodifiableNavigableSet", e);
        }
    }

    @Override
    public void write(Kryo kryo, Output output, NavigableSet<?> object) {
        // We want to preserve the underlying delegate class, so we need to reflectively get it and write it directly via kryo
        kryo.writeClassAndObject(output, getDelegateFromUnmodifiableNavigableSet(object));
    }

    @Override
    public NavigableSet<?> read(Kryo kryo, Input input, Class<? extends NavigableSet<?>> type) {
        return Sets.unmodifiableNavigableSet((NavigableSet<?>) kryo.readClassAndObject(input));
    }

    @Override
    public NavigableSet<?> copy(Kryo kryo, NavigableSet<?> original) {
        return Sets.unmodifiableNavigableSet((NavigableSet<?>) kryo.copy(getDelegateFromUnmodifiableNavigableSet(original)));
    }

    /**
     * Creates a new {@link UnmodifiableNavigableSetSerializer} and registers its serializer
     * for the UnmodifiableNavigableSetSerializer related class.
     *
     * @param kryo the {@link Kryo} instance to set the serializer on
     */
    public static void registerSerializers(final Kryo kryo) {

        // UnmodifiableNavigableSetSerializer (private class)

        final UnmodifiableNavigableSetSerializer serializer = new UnmodifiableNavigableSetSerializer();

        kryo.register(Sets.unmodifiableNavigableSet(new TreeSet<Object>()).getClass(), serializer);
    }
}


package de.javakaffee.kryoserializers;

import static com.esotericsoftware.minlog.Log.TRACE;
import static com.esotericsoftware.minlog.Log.trace;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.SerializerFactory;
import com.esotericsoftware.kryo.serializers.FieldSerializer;

/**
 * A kryo {@link FieldSerializer} that allows to exclusively include or exclude fields that
 * are attributed with user-specific annotations. This can be for example useful when serializing beans that carry
 * references to a dependency injection framework. As an example for Spring:
 *

 *

 * {@code
 * Set<Class<? extends Annotation>> marks = new HashSet<>();
 * marks.add(Autowired.class);
 * SerializerFactory disregardingFactory = new FieldAnnotationAwareSerializer.Factory(marks, true);
 * Kryo kryo = new Kryo();
 * kryo.setDefaultSerializer(factory);
 * }
 *

 *

 * The resulting {@link Kryo} instance would ignore all fields that are annotated with Spring's {@code @Autowired}
 * annotation.
 *

 * Similarly, it is possible to created a serializer which does the opposite such that the resulting serializer
 * would only serialize fields that are annotated with the specified annotations.
 *
 * @author Rafael Winterhalter
 * @author Martin Grotzke
 */
public class FieldAnnotationAwareSerializer<T> extends FieldSerializer<T> {

    /**
     * A factory for creating instances of {@link FieldAnnotationAwareSerializer}.
     */
    public static class Factory implements SerializerFactory<FieldAnnotationAwareSerializer<Object>> {

        private final Collection<Class<? extends Annotation>> marked;
        private final boolean disregarding;

        /**
         * Creates a new factory. See {@link FieldAnnotationAwareSerializer#FieldAnnotationAwareSerializer(
         *com.esotericsoftware.kryo.Kryo, Class, java.util.Collection, boolean)}
         * for additional information on the constructor parameters.
         *
         * @param marked       The annotations that will be considered of the resulting converter.
         * @param disregarding If {@code true}, the serializer will ignore all annotated fields,
         *                     if set to {@code false} it will exclusively look at annotated fields.
         */
        public Factory(final Collection<Class<? extends Annotation>> marked, final boolean disregarding) {
            this.marked = marked;
            this.disregarding = disregarding;
        }

        @Override
        public boolean isSupported(Class type) {
            return true;
        }

        @Override
        public FieldAnnotationAwareSerializer<Object> newSerializer(final Kryo kryo, final Class type) {
            return new FieldAnnotationAwareSerializer<Object>(kryo, type, marked, disregarding);
        }
    }

    private final Set<Class<? extends Annotation>> marked;

    /**
     * Determines whether annotated fields should be excluded from serialization.
     *

     * {@code true} if annotated fields should be excluded from serialization,
     * {@code false} if only annotated fields should be included from serialization.
     */
    private final boolean disregarding;

    /**
     * Creates a new field annotation aware serializer.
     *
     * @param kryo         The {@link Kryo} instace.
     * @param type         The type of the class being serialized.
     * @param marked       The annotations this serializer considers for its serialization process. Be aware tha
     *                     a serializer with {@code disregarding} set to {@code false} will never be able to
     *                     serialize fields that are not annotated with any of these annotations since it is not
     *                     possible to add fields to a {@link FieldSerializer} once it is created. See the
     *                     documentation to {@link FieldAnnotationAwareSerializer#addAnnotation(Class)} and
     *                     {@link FieldAnnotationAwareSerializer#removeAnnotation(Class)} for further information.
     * @param disregarding If {@code true}, the serializer will ignore all annotated fields,
     *                     if set to {@code false} it will exclusively look at annotated fields.
     */
    public FieldAnnotationAwareSerializer(final Kryo kryo,
                                          final Class<?> type,
                                          final Collection<Class<? extends Annotation>> marked,
                                          final boolean disregarding) {
        super(kryo, type);
        this.disregarding = disregarding;
        this.marked = new HashSet<Class<? extends Annotation>>(marked);

        removeFields();
    }

    @Override
    public void updateFields() {
        // In order to avoid rebuilding the cached fields twice, the super constructor's call
        // to this method will be suppressed. This can be done by a simple check of the initialization
        // state of a property of this subclass.
        if (marked == null) {
            return;
        }

        super.updateFields();
        removeFields();
    }

    private void removeFields() {
        final CachedField[] cachedFields = getFields();
        for (final CachedField cachedField : cachedFields) {
            final Field field = cachedField.getField();
            if (isRemove(field)) {
                if (TRACE) {
                    trace("kryo", String.format("Ignoring field %s tag: %s", disregarding ? "without" : "with", cachedField));
                }
                super.removeField(field.getName());
            }
        }
    }

    private boolean isRemove(final Field field) {
        return !isMarked(field) ^ disregarding;
    }

    private boolean isMarked(final Field field) {
        for (final Annotation annotation : field.getAnnotations()) {
            final Class<? extends Annotation> annotationType = annotation.annotationType();
            if (marked.contains(annotationType)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Adds an annotation to the annotations that are considered by this serializer.
     *

     * Important: This will not have an effect if the serializer was configured
     * to exclusively serialize annotated fields by setting {@code disregarding} to
     * {@code false}. This is similar to the contract of this serializer's superclass
     * {@link FieldSerializer} which does not allow to add fields that were formerly
     * removed. If this was possible, instances that were serialized before this field
     * was added could not longer be properly deserialized. In order to make this contract
     * break explicit, you need to create a new instance of this serializer if you want to
     * include new fields to a serializer that exclusively serializes annotated fields.
     *
     * @param clazz The annotation class to be added.
     * @return {@code true} if the method call had an effect.
     */
    public boolean addAnnotation(final Class<? extends Annotation> clazz) {
        if (disregarding && marked.add(clazz)) {
            initializeCachedFields();
            return true;
        }
        return false;
    }

    /**
     * Removes an annotation to the annotations that are considered by this serializer.
     *

     * Important: This will not have an effect if the serializer was configured
     * to not serialize annotated fields by setting {@code disregarding} to
     * {@code true}. This is similar to the contract of this serializer's superclass
     * {@link FieldSerializer} which does not allow to add fields that were formerly
     * removed. If this was possible, instances that were serialized before this field
     * was added could not longer be properly deserialized. In order to make this contract
     * break explicit, you need to create a new instance of this serializer if you want to
     * include new fields to a serializer that ignores annotated fields for serialization.
     *
     * @param clazz The annotation class to be removed.
     * @return {@code true} if the method call had an effect.
     */
    public boolean removeAnnotation(final Class<? extends Annotation> clazz) {
        if (!disregarding && marked.remove(clazz)) {
            initializeCachedFields();
            return true;
        }
        return false;
    }
}


package de.javakaffee.kryoserializers.guava;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Registration;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.google.common.collect.ArrayTable;
import com.google.common.collect.ImmutableList;

import java.util.List;

/**
 * A kryo {@link Serializer} for guava-libraries {@link ArrayTable}.
 */
public class ArrayTableSerializer<R, C, V> extends TableSerializerBase<R, C, V, ArrayTable<R, C, V>> {

    private static final boolean HANDLES_NULL = false;
    private static final boolean IMMUTABLE = false;

    public ArrayTableSerializer() {
        super(HANDLES_NULL, IMMUTABLE);
    }

    @Override
    public void write(Kryo kryo, Output output, ArrayTable<R, C, V> table) {
        List<R> rowKeys = table.rowKeyList();
        List<C> columnKeys = table.columnKeyList();
        kryo.writeClassAndObject(output, rowKeys);
        kryo.writeClassAndObject(output, columnKeys);
        for (R rowKey : rowKeys) {
            for (C columnKey : columnKeys) {
                V val = table.get(rowKey, columnKey);
                kryo.writeClassAndObject(output, val);
            }
        }
    }

    @Override
    public ArrayTable<R, C, V> read(Kryo kryo, Input input, Class<? extends ArrayTable<R, C, V>> type) {
        List<R> rowKeys = (List<R>) kryo.readClassAndObject(input);
        List<C> columnKeys = (List<C>) kryo.readClassAndObject(input);
        ArrayTable<R, C, V> table = ArrayTable.create(rowKeys, columnKeys);
        for (R rowKey : rowKeys) {
            for (C columnKey : columnKeys) {
                V val = (V) kryo.readClassAndObject(input);
                table.put(rowKey, columnKey, val);
            }
        }
        return table;
    }

    @Override
    public ArrayTable<R, C, V> copy(final Kryo kryo, final ArrayTable<R, C, V> original) {
        return ArrayTable.create(original);
    }

    /* kryo.getSerializer (invoking kryo.getRegistration) throws an exception if registration is required,
     * therefore we're getting a potentially existing serializer on another way.
     */
    private static Serializer<?> getSerializer(Kryo kryo, Class<?> type) {
        Registration registration = kryo.getClassResolver().getRegistration(type);
        return registration != null ? registration.getSerializer() : null;
    }

    /**
     * Creates a new {@link ArrayTableSerializer} and registers its serializer.
     *
     * @param kryo the {@link Kryo} instance to set the serializer on
     */
    public static void registerSerializers(final Kryo kryo) {

        // ImmutableList is used by ArrayTable. However,
        // we already have a separate serializer class for ImmutableList,
        // ImmutableListSerializer. If it is not already being used, register it.
        Serializer immutableListSerializer = getSerializer(kryo, ImmutableList.class);
        if (!(immutableListSerializer instanceof ImmutableListSerializer)) {
            ImmutableListSerializer.registerSerializers(kryo);
        }

        final ArrayTableSerializer serializer = new ArrayTableSerializer();
        kryo.register(ArrayTable.class, serializer);
    }
}


package de.javakaffee.kryoserializers.guava;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Maps;

import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;

/**
 * A kryo {@link Serializer} for guava-libraries {@link ImmutableMap}.
 */
public class ImmutableMapSerializer extends Serializer<ImmutableMap<Object, ? extends Object>> {

    private static final boolean DOES_NOT_ACCEPT_NULL = true;
    private static final boolean IMMUTABLE = true;

    public ImmutableMapSerializer() {
        super(DOES_NOT_ACCEPT_NULL, IMMUTABLE);
    }

    @Override
    public void write(Kryo kryo, Output output, ImmutableMap<Object, ? extends Object> immutableMap) {
        kryo.writeObject(output, Maps.newHashMap(immutableMap));
    }

    @Override
    public ImmutableMap<Object, Object> read(Kryo kryo, Input input, Class<? extends ImmutableMap<Object, ? extends Object>> type) {
        Map map = kryo.readObject(input, HashMap.class);
        return ImmutableMap.copyOf(map);
    }

    /**
     * Creates a new {@link ImmutableMapSerializer} and registers its serializer
     * for the several ImmutableMap related classes.
     *
     * @param kryo the {@link Kryo} instance to set the serializer on
     */
    public static void registerSerializers(final Kryo kryo) {

        // we're writing a HashMap, therefore we should register it
        kryo.register(java.util.HashMap.class);

        final ImmutableMapSerializer serializer = new ImmutableMapSerializer();

        // ImmutableMap (abstract class)
        //  +- EmptyImmutableBiMap
        //  +- SingletonImmutableBiMap
        //  +- RegularImmutableMap
        //  +- ImmutableEnumMap
        //  +- RowMap from DenseImmutableTable
        //  +- Row from DenseImmutableTable
        //  +- ColumnMap from DenseImmutableTable
        //  +- Column from DenseImmutableTable

        kryo.register(ImmutableMap.class, serializer);
        kryo.register(ImmutableMap.of().getClass(), serializer);

        Object o1 = new Object();
        Object o2 = new Object();

        kryo.register(ImmutableMap.of(o1, o1).getClass(), serializer);
        kryo.register(ImmutableMap.of(o1, o1, o2, o2).getClass(), serializer);

        Map<DummyEnum, Object> enumMap = new EnumMap<DummyEnum, Object>(DummyEnum.class);
        for (DummyEnum e : DummyEnum.values()) {
            enumMap.put(e, o1);
        }

        kryo.register(ImmutableMap.copyOf(enumMap).getClass(), serializer);

        ImmutableTable<Object, Object, Object> denseImmutableTable = ImmutableTable.builder()
                .put("a", 1, 1)
                .put("b", 1, 1)
                .build();

        kryo.register(denseImmutableTable.rowMap().getClass(), serializer); // RowMap
        kryo.register(denseImmutableTable.rowMap().get("a").getClass(), serializer); // Row
        kryo.register(denseImmutableTable.columnMap().getClass(), serializer); // ColumnMap
        kryo.register(denseImmutableTable.columnMap().get(1).getClass(), serializer); // Column
    }

    private enum DummyEnum {
        VALUE1,
        VALUE2
    }
}


package de.javakaffee.kryoserializers.dexx;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;

import com.github.andrewoma.dexx.collection.IndexedLists;
import com.github.andrewoma.dexx.collection.List;

/**
 * A kryo {@link Serializer} for dexx {@link List}
 */
public class ListSerializer extends Serializer<List> {

    private static final boolean DOES_NOT_ACCEPT_NULL = true;
    private static final boolean IMMUTABLE = true;

    public ListSerializer() {
        super(DOES_NOT_ACCEPT_NULL, IMMUTABLE);
    }

    @Override
    public void write(Kryo kryo, Output output, List object) {
        output.writeInt(object.size(), true);
        for (Object elm : object) {
            kryo.writeClassAndObject(output, elm);
        }
    }

    @Override
    public List<Object> read(Kryo kryo, Input input, Class<? extends List> aClass) {
        final int size = input.readInt(true);
        final Object[] list = new Object[size];
        for (int i = 0; i < size; ++i) {
            list[i] = kryo.readClassAndObject(input);
        }
        return IndexedLists.copyOf(list);
    }

    /**
     * Creates a new {@link  ImmutableListSerializer} and registers its serializer
     *
     * @param kryo the {@link Kryo} instance to set the serializer on
     */
    public static void registerSerializers(final Kryo kryo) {

        final ListSerializer serializer = new ListSerializer();

        kryo.register(List.class, serializer);

        // Note:
        //  Only registering above is good enough for serializing/deserializing.
        //  but if using Kryo#copy, following is required.

        kryo.register(IndexedLists.of().getClass(), serializer);
        kryo.register(IndexedLists.of(1).getClass(), serializer);
        kryo.register(IndexedLists.of(1,2).getClass(), serializer);
        kryo.register(IndexedLists.of(1,2,3).getClass(), serializer);
        kryo.register(IndexedLists.of(1,2,3,4).getClass(), serializer);
        kryo.register(IndexedLists.of(1,2,3,4,5).getClass(), serializer);
        kryo.register(IndexedLists.of(1,2,3,4,5,6).getClass(), serializer);
        kryo.register(IndexedLists.of(1,2,3,4,5,6,7).getClass(), serializer);
        kryo.register(IndexedLists.of(1,2,3,4,5,6,7,8).getClass(), serializer);
        kryo.register(IndexedLists.of(1,2,3,4,5,6,7,8,9).getClass(), serializer);
        kryo.register(IndexedLists.of(1,2,3,4,5,6,7,8,10).getClass(), serializer);
        kryo.register(IndexedLists.of(1,2,3,4,5,6,7,8,10,11).getClass(), serializer);

    }
}


package de.javakaffee.kryoserializers.dexx;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;

import com.github.andrewoma.dexx.collection.Map;
import com.github.andrewoma.dexx.collection.Maps;
import com.github.andrewoma.dexx.collection.Pair;

import java.util.HashMap;
import java.util.ArrayList;
import java.util.Map.Entry;

/**
* A kryo {@link Serializer} for dexx {@link Map}
 */
public class MapSerializer extends Serializer<Map<Object, ? extends Object>> {

    private static final boolean DOES_NOT_ACCEPT_NULL = true;
    private static final boolean IMMUTABLE = true;

    public MapSerializer() {
        super(DOES_NOT_ACCEPT_NULL, IMMUTABLE);
    }

    @Override
    public void write(Kryo kryo, Output output, Map<Object, ? extends Object> immutableMap) {
        kryo.writeObject(output, immutableMap.asMap());
    }

    @Override
    public Map<Object, Object> read(Kryo kryo, Input input, Class<? extends Map<Object, ? extends Object>> type) {
        HashMap<Object, Object> map = kryo.readObject(input, HashMap.class);
        ArrayList<Pair<Object, Object>> listOfPairs = new ArrayList();

        for (Entry<Object, Object> entry : map.entrySet()) {
            Pair pair = new Pair(entry.getKey(), entry.getValue());
            listOfPairs.add(pair);
        }

        return Maps.copyOf(listOfPairs);
    }

    /**
     * Creates a new {@link ImmutableMapSerializer} and registers its serializer
     * for the several ImmutableMap related classes.
     *
     * @param kryo the {@link Kryo} instance to set the serializer on
     */
     public static void registerSerializers(final Kryo kryo) {

         final MapSerializer serializer = new MapSerializer();

         kryo.register(Map.class, serializer);
         kryo.register(Maps.of().getClass(), serializer);

         Object o1 = new Object();
         Object o2 = new Object();
         Object o3 = new Object();
         Object o4 = new Object();
         Object o5 = new Object();

         kryo.register(Maps.of(o1, o1).getClass(), serializer);
         kryo.register(Maps.of(o1, o1, o2, o2).getClass(), serializer);
         kryo.register(Maps.of(o1, o1, o2, o2, o3, o3).getClass(), serializer);
         kryo.register(Maps.of(o1, o1, o2, o2, o3, o3, o4, o4).getClass(), serializer);
         kryo.register(Maps.of(o1, o1, o2, o2, o3, o3, o4, o4, o5, o5).getClass(), serializer);

     }
}


package de.javakaffee.kryoserializers.guava;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.google.common.collect.Multimap;
import com.google.common.collect.TreeMultimap;

import java.util.Comparator;

/**
 * A kryo {@link Serializer} for guava-libraries {@link TreeMultimap}.
 * For reading / writing, the default comparator is assumed so the multimaps are not null-safe.
 * For copying, the copy contains the same comparator instances as the original.
 */
public class TreeMultimapSerializer extends MultimapSerializerBase<Comparable, Comparable, TreeMultimap<Comparable, Comparable>> {

    /* assumes default comparator */
    private static final boolean DOES_NOT_ACCEPT_NULL = true;

    private static final boolean IMMUTABLE = false;

    public TreeMultimapSerializer() {
        super(DOES_NOT_ACCEPT_NULL, IMMUTABLE);
    }

    @Override
    public void write(Kryo kryo, Output output, TreeMultimap<Comparable, Comparable> multimap) {
        kryo.writeClassAndObject(output, multimap.keyComparator());
        kryo.writeClassAndObject(output, multimap.valueComparator());
        writeMultimap(kryo, output, multimap);
    }

    @Override
    public TreeMultimap<Comparable, Comparable> read(Kryo kryo, Input input, Class<? extends TreeMultimap<Comparable, Comparable>> type) {
        Comparator<? super Comparable> keyComparator = (Comparator<? super Comparable>) kryo.readClassAndObject(input);
        Comparator<? super Comparable> valueComparator = (Comparator<? super Comparable>) kryo.readClassAndObject(input);
        final TreeMultimap<Comparable, Comparable> multimap = TreeMultimap.create(keyComparator, valueComparator);
        readMultimap(kryo, input, multimap);
        return multimap;
    }

    @Override
    protected Multimap createCopy(Kryo kryo, Multimap original) {
        TreeMultimap tm = (TreeMultimap) original;
        return TreeMultimap.create(tm.keyComparator(), tm.valueComparator());
    }

    /**
     * Creates a new {@link TreeMultimapSerializer} and registers its serializer.
     *
     * @param kryo the {@link Kryo} instance to set the serializer on
     */
    public static void registerSerializers(final Kryo kryo) {
        final TreeMultimapSerializer serializer = new TreeMultimapSerializer();
        kryo.register(TreeMultimap.class, serializer);
    }
}


/*
 * Copyright 2010 Martin Grotzke
 *
 * 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 de.javakaffee.kryoserializers;

import java.lang.reflect.Field;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;

/**
 * Kryo {@link Serializer}s for lists created via {@link List#subList(int, int)}.
 * An instance of a serializer can be obtained via {@link #createFor(Class)}, which
 * just returns null if the given type is not supported by these
 * serializers.
 *
 * @author Martin Grotzke
 */
public class SubListSerializers {

    static Class<?> getClass(final String className) {
        try {
            return Class.forName(className);
        } catch (final Exception e) {
            throw new RuntimeException(e);
        }
    }

    static Class<?> getClassOrNull(final String className) {
        try {
            return Class.forName(className);
        } catch (final Exception e) {
            return null;
        }
    }

    // Workaround reference reading, this should be removed sometimes. See also
    // https://groups.google.com/d/msg/kryo-users/Eu5V4bxCfws/k-8UQ22y59AJ
    private static final Object FAKE_REFERENCE = new Object();

    /**
     * Obtain a serializer for the given sublist type. If the type is not supported
     * null is returned.
     * @param type the class of the sublist.
     * @return a serializer instance or null.
     */
    @SuppressWarnings("rawtypes")
    public static Serializer<List<?>> createFor(final Class type) {
        if (ArrayListSubListSerializer.canSerialize(type))
            return new ArrayListSubListSerializer();
        if (JavaUtilSubListSerializer.canSerialize(type))
            return new JavaUtilSubListSerializer();
        return null;
    }

    /**
     * Adds appropriate sublist serializers as default serializers.
     */
    public static Kryo addDefaultSerializers(Kryo kryo) {
        ArrayListSubListSerializer.addDefaultSerializer(kryo);
        AbstractListSubListSerializer.addDefaultSerializer(kryo);
        JavaUtilSubListSerializer.addDefaultSerializer(kryo);
        return kryo;
    }

    /**
     * Supports sublists created via {@link ArrayList#subList(int, int)} since java7 and {@link LinkedList#subList(int, int)} since java9 (openjdk).
     */
    private static class SubListSerializer extends Serializer<List<?>> {

        private Field _parentField;
        private Field _parentOffsetField;
        private Field _sizeField;

        public SubListSerializer(String subListClassName) {
            try {
                final Class<?> clazz = Class.forName(subListClassName);
                _parentField = getParentField(clazz);
                _parentOffsetField = getOffsetField(clazz);
                _sizeField = clazz.getDeclaredField( "size" );
                _parentField.setAccessible( true );
                _parentOffsetField.setAccessible( true );
                _sizeField.setAccessible( true );
            } catch (final Exception e) {
                throw new RuntimeException(e);
            }
        }

        private static Field getParentField(Class clazz) throws NoSuchFieldException {
            try {
                // java 9+
                return clazz.getDeclaredField("root");
            } catch(NoSuchFieldException e) {
                return clazz.getDeclaredField("parent");
            }
        }

        private static Field getOffsetField(Class<?> clazz) throws NoSuchFieldException {
            try {
                // up to jdk8 (which also has an "offset" field (we don't need) - therefore we check "parentOffset" first
                return clazz.getDeclaredField( "parentOffset" );
            } catch (NoSuchFieldException e) {
                // jdk9+ only has "offset" which is the parent offset
                return clazz.getDeclaredField( "offset" );
            }
        }

        @Override
        public List<?> read(final Kryo kryo, final Input input, final Class<? extends List<?>> clazz) {
            kryo.reference(FAKE_REFERENCE);
            final List<?> list = (List<?>) kryo.readClassAndObject(input);
            final int fromIndex = input.readInt(true);
            final int toIndex = input.readInt(true);
            return list.subList(fromIndex, toIndex);
        }

        @Override
        public void write(final Kryo kryo, final Output output, final List<?> obj) {
            try {
                kryo.writeClassAndObject(output, _parentField.get(obj));
                final int parentOffset = _parentOffsetField.getInt( obj );
                final int fromIndex = parentOffset;
                output.writeInt(fromIndex, true);
                final int toIndex = fromIndex + _sizeField.getInt( obj );
                output.writeInt(toIndex, true);
            } catch (final RuntimeException e) {
                // Don't eat and wrap RuntimeExceptions because the ObjectBuffer.write...
                // handles SerializationException specifically (resizing the buffer)...
                throw e;
            } catch (final Exception e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public List<?> copy(final Kryo kryo, final List<?> original) {
            kryo.reference(FAKE_REFERENCE);
            try {
                final List<?> list = (List<?>) _parentField.get(original);
                final int parentOffset = _parentOffsetField.getInt( original );
                final int fromIndex = parentOffset;
                final int toIndex = fromIndex + _sizeField.getInt( original );
                return kryo.copy(list).subList(fromIndex, toIndex);
            } catch(final Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * Supports sublists created via {@link ArrayList#subList(int, int)} since java7 (oracle jdk,
     * represented by java.util.ArrayList$SubList).
     */
    public static class ArrayListSubListSerializer extends Serializer<List<?>> {

        public static final Class<?> SUBLIST_CLASS = SubListSerializers.getClassOrNull("java.util.ArrayList$SubList");

        private final SubListSerializer delegate = new SubListSerializer("java.util.ArrayList$SubList");

        /**
         * Can be used to determine, if the given type can be handled by this serializer.
         *
         * @param type
         *            the class to check.
         * @return true if the given class can be serialized/deserialized by this serializer.
         */
        public static boolean canSerialize(final Class<?> type) {
            return SUBLIST_CLASS != null && SUBLIST_CLASS.isAssignableFrom(type);
        }

        public static Kryo addDefaultSerializer(Kryo kryo) {
            if(SUBLIST_CLASS != null) kryo.addDefaultSerializer(SUBLIST_CLASS, new ArrayListSubListSerializer());
            return kryo;
        }

        @Override
        public List<?> read(final Kryo kryo, final Input input, final Class<? extends List<?>> clazz) {
            return delegate.read(kryo, input, clazz);
        }

        @Override
        public void write(final Kryo kryo, final Output output, final List<?> obj) {
            delegate.write(kryo, output, obj);
        }

        @Override
        public List<?> copy(final Kryo kryo, final List<?> original) {
            return delegate.copy(kryo, original);
        }
    }

    /**
     * Supports sublists created via {@link LinkedList#subList(int, int)} since java9 (oracle jdk,
     * represented by java.util.AbstractList$SubList).
     */
    public static class AbstractListSubListSerializer extends Serializer<List<?>> {

        public static final Class<?> SUBLIST_CLASS = SubListSerializers.getClassOrNull("java.util.AbstractList$SubList");

        private final SubListSerializer delegate = new SubListSerializer("java.util.AbstractList$SubList");

        /**
         * Can be used to determine, if the given type can be handled by this serializer.
         *
         * @param type
         *            the class to check.
         * @return true if the given class can be serialized/deserialized by this serializer.
         */
        public static boolean canSerialize(final Class<?> type) {
            return SUBLIST_CLASS != null && SUBLIST_CLASS.isAssignableFrom(type);
        }

        public static Kryo addDefaultSerializer(Kryo kryo) {
            if(SUBLIST_CLASS != null) kryo.addDefaultSerializer(SUBLIST_CLASS, new AbstractListSubListSerializer());
            return kryo;
        }

        @Override
        public List<?> read(final Kryo kryo, final Input input, final Class<? extends List<?>> clazz) {
            return delegate.read(kryo, input, clazz);
        }

        @Override
        public void write(final Kryo kryo, final Output output, final List<?> obj) {
            delegate.write(kryo, output, obj);
        }

        @Override
        public List<?> copy(final Kryo kryo, final List<?> original) {
            return delegate.copy(kryo, original);
        }
    }

    /**
     * Supports sublists created via {@link AbstractList#subList(int, int)}, e.g. LinkedList.
     * In oracle jdk such sublists are represented by java.util.SubList.
     */
    public static class JavaUtilSubListSerializer extends Serializer<List<?>> {

        public static final Class<?> SUBLIST_CLASS = SubListSerializers.getClassOrNull("java.util.SubList");

        private Field _listField;
        private Field _offsetField;
        private Field _sizeField;

        public JavaUtilSubListSerializer() {
            try {
                final Class<?> clazz = Class.forName("java.util.SubList");
                _listField = clazz.getDeclaredField("l");
                _offsetField = clazz.getDeclaredField("offset");
                _sizeField = clazz.getDeclaredField("size");
                _listField.setAccessible(true);
                _offsetField.setAccessible(true);
                _sizeField.setAccessible(true);
            } catch (final Exception e) {
                throw new RuntimeException(e);
            }
        }

        /**
         * Can be used to determine, if the given type can be handled by this serializer.
         *
         * @param type
         *            the class to check.
         * @return true if the given class can be serialized/deserialized by this serializer.
         */
        public static boolean canSerialize(final Class<?> type) {
            return SUBLIST_CLASS != null && SUBLIST_CLASS.isAssignableFrom(type);
        }

        public static Kryo addDefaultSerializer(Kryo kryo) {
            if(SUBLIST_CLASS != null) kryo.addDefaultSerializer(SUBLIST_CLASS, new JavaUtilSubListSerializer());
            return kryo;
        }

        @Override
        public List<?> read(final Kryo kryo, final Input input, final Class<? extends List<?>> clazz) {
            kryo.reference(FAKE_REFERENCE);
            final List<?> list = (List<?>) kryo.readClassAndObject(input);
            final int fromIndex = input.readInt(true);
            final int toIndex = input.readInt(true);
            return list.subList(fromIndex, toIndex);
        }

        @Override
        public void write(final Kryo kryo, final Output output, final List<?> obj) {
            try {
                kryo.writeClassAndObject(output, _listField.get(obj));
                final int fromIndex = _offsetField.getInt(obj);
                output.writeInt(fromIndex, true);
                final int toIndex = fromIndex + _sizeField.getInt(obj);
                output.writeInt(toIndex, true);
            } catch (final RuntimeException e) {
                // Don't eat and wrap RuntimeExceptions because the ObjectBuffer.write...
                // handles SerializationException specifically (resizing the buffer)...
                throw e;
            } catch (final Exception e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public List<?> copy(final Kryo kryo, final List<?> obj) {
            kryo.reference(FAKE_REFERENCE);
            try {
                final List<?> list = (List<?>) _listField.get(obj);
                final int fromIndex = _offsetField.getInt(obj);
                final int toIndex = fromIndex + _sizeField.getInt(obj);
                return kryo.copy(list).subList(fromIndex, toIndex);
            } catch(final Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}


package de.javakaffee.kryoserializers.guava;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Maps;

import java.util.EnumMap;
import java.util.Map;
import java.util.TreeMap;

/**
 * A kryo {@link Serializer} for guava-libraries {@link ImmutableSortedMap}.
 */
public class ImmutableSortedMapSerializer extends Serializer<ImmutableSortedMap<Object, ? extends Object>> {

    private static final boolean DOES_NOT_ACCEPT_NULL = true;
    private static final boolean IMMUTABLE = true;

    public ImmutableSortedMapSerializer() {
        super(DOES_NOT_ACCEPT_NULL, IMMUTABLE);
    }

    @Override
    public void write(Kryo kryo, Output output, ImmutableSortedMap<Object, ? extends Object> immutableMap) {
        kryo.writeObject(output, Maps.newTreeMap(immutableMap));
    }

    @Override
    public ImmutableSortedMap<Object, Object> read(Kryo kryo, Input input, Class<? extends ImmutableSortedMap<Object, ? extends Object>> type) {
        Map map = kryo.readObject(input, TreeMap.class);
        return ImmutableSortedMap.copyOf(map);
    }

    /**
     * Creates a new {@link ImmutableSortedMapSerializer} and registers its serializer
     * for the several ImmutableMap related classes.
     *
     * @param kryo the {@link Kryo} instance to set the serializer on
     */
    public static void registerSerializers(final Kryo kryo) {

        // we're writing a TreeMap, therefore we should register it
        kryo.register(java.util.TreeMap.class);

        final ImmutableSortedMapSerializer serializer = new ImmutableSortedMapSerializer();

        kryo.register(ImmutableSortedMap.class, serializer);
        kryo.register(ImmutableSortedMap.of().getClass(), serializer);

        final Comparable<Object> k1 = new Comparable<Object>() {
            @Override
            public int compareTo(Object o) {
                return o == this ? 0 : -1;
            }
        };
        final Comparable<Object> k2 = new Comparable<Object>() {
            @Override
            public int compareTo(Object o) {
                return o == this ? 0 : 1;
            }
        };
        final Object v1 = new Object();
        final Object v2 = new Object();

        kryo.register(ImmutableSortedMap.of(k1, v1).getClass(), serializer);
        kryo.register(ImmutableSortedMap.of(k1, v1, k2, v2).getClass(), serializer);

        Map<DummyEnum,Object> enumMap = new EnumMap<DummyEnum, Object>(DummyEnum.class);
        for (DummyEnum e : DummyEnum.values()) {
            enumMap.put(e, v1);
        }

        kryo.register(ImmutableSortedMap.copyOf(enumMap).getClass(), serializer);
    }

    private enum DummyEnum {
        VALUE1,
        VALUE2
    }
}


package de.javakaffee.kryoserializers.guava;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;

/**
 * A kryo {@link Serializer} for guava-libraries {@link ImmutableSet}.
 *
 *@implNote ImmutableSet builder would be a little bit more efficient for less than five elements
 *(the array.clone as done by copyOf is saved), for more elements copyOf seems to get more efficient.
 */
public class ImmutableSetSerializer extends Serializer<ImmutableSet<Object>> {

    private static final boolean DOES_NOT_ACCEPT_NULL = false;
    private static final boolean IMMUTABLE = true;

    public ImmutableSetSerializer() {
        super(DOES_NOT_ACCEPT_NULL, IMMUTABLE);
    }

    @Override
    public void write(Kryo kryo, Output output, ImmutableSet<Object> object) {
        output.writeInt(object.size(), true);
        for (Object elm : object) {
            kryo.writeClassAndObject(output, elm);
        }
    }

    @Override
    public ImmutableSet<Object> read(Kryo kryo, Input input, Class<? extends ImmutableSet<Object>> type) {
        final int size = input.readInt(true);
        ImmutableSet.Builder<Object> builder = ImmutableSet.builder();
        for (int i = 0; i < size; ++i) {
            builder.add(kryo.readClassAndObject(input));
        }
        return builder.build();
    }

    /**
     * Creates a new {@link ImmutableSetSerializer} and registers its serializer
     * for the several ImmutableSet related classes.
     *
     * @param kryo the {@link Kryo} instance to set the serializer on
     */
    public static void registerSerializers(final Kryo kryo) {

        // ImmutableList (abstract class)
        //  +- EmptyImmutableSet
        //  |   EmptyImmutableSet
        //  +- SingletonImmutableSet
        //  |   Optimized for Set with only 1 element.
        //  +- RegularImmutableSet
        //  |   RegularImmutableList
        //  +- EnumImmutableSet
        //  |   EnumImmutableSet

        final ImmutableSetSerializer serializer = new ImmutableSetSerializer();

        kryo.register(ImmutableSet.class, serializer);

        // Note:
        //  Only registering above is good enough for serializing/deserializing.
        //  but if using Kryo#copy, following is required.

        kryo.register(ImmutableSet.of().getClass(), serializer);
        kryo.register(ImmutableSet.of(1).getClass(), serializer);
        kryo.register(ImmutableSet.of(1,2,3).getClass(), serializer);

        kryo.register(Sets.immutableEnumSet(SomeEnum.A, SomeEnum.B, SomeEnum.C).getClass(), serializer);
    }

    private enum SomeEnum {
        A, B, C
    }
}


package de.javakaffee.kryoserializers.guava;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;

/**
 * A kryo {@link Serializer} for guava-libraries {@link HashMultimap}.
 */
public class HashMultimapSerializer extends MultimapSerializerBase<Object, Object, HashMultimap<Object, Object>> {

    private static final boolean DOES_NOT_ACCEPT_NULL = false;

    private static final boolean IMMUTABLE = false;

    public HashMultimapSerializer() {
        super(DOES_NOT_ACCEPT_NULL, IMMUTABLE);
    }

    @Override
    public void write(Kryo kryo, Output output, HashMultimap<Object, Object> multimap) {
        writeMultimap(kryo, output, multimap);
    }

    @Override
    public HashMultimap<Object, Object> read(Kryo kryo, Input input, Class<? extends HashMultimap<Object, Object>> type) {
        final HashMultimap<Object, Object> multimap = HashMultimap.create();
        readMultimap(kryo, input, multimap);
        return multimap;
    }

    @Override
    public Multimap createCopy(Kryo kryo, Multimap original) {
        return HashMultimap.create();
    }

    /**
     * Creates a new {@link HashMultimapSerializer} and registers its serializer.
     *
     * @param kryo the {@link Kryo} instance to set the serializer on
     */
    public static void registerSerializers(final Kryo kryo) {
        final HashMultimapSerializer serializer = new HashMultimapSerializer();
        kryo.register(HashMultimap.class, serializer);
    }
}


/*
 * Copyright 2010 Martin Grotzke
 *
 * 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 de.javakaffee.kryoserializers;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;

/**
 * A kryo {@link Serializer} for unmodifiable {@link Collection}s and {@link Map}s
 * created via {@link Collections}.
 *
 * @author Martin Grotzke
 */
public class UnmodifiableCollectionsSerializer extends Serializer<Object> {

    private static final Field SOURCE_COLLECTION_FIELD;
    private static final Field SOURCE_MAP_FIELD;

    static {
        try {
            SOURCE_COLLECTION_FIELD = Class.forName("java.util.Collections$UnmodifiableCollection" )
                .getDeclaredField( "c" );
            SOURCE_COLLECTION_FIELD.setAccessible( true );

            SOURCE_MAP_FIELD = Class.forName("java.util.Collections$UnmodifiableMap" )
                .getDeclaredField( "m" );
            SOURCE_MAP_FIELD.setAccessible( true );
        } catch ( final Exception e ) {
            throw new RuntimeException( "Could not access source collection" +
                    " field in java.util.Collections$UnmodifiableCollection.", e );
        }
    }

    @Override
    public Object read(final Kryo kryo, final Input input, final Class<? extends Object> clazz) {
        final int ordinal = input.readInt( true );
        final UnmodifiableCollection unmodifiableCollection = UnmodifiableCollection.values()[ordinal];
        final Object sourceCollection = kryo.readClassAndObject( input );
        return unmodifiableCollection.create( sourceCollection );
    }

    @Override
    public void write(final Kryo kryo, final Output output, final Object object) {
        try {
            final UnmodifiableCollection unmodifiableCollection = UnmodifiableCollection.valueOfType( object.getClass() );
            // the ordinal could be replaced by s.th. else (e.g. a explicitely managed "id")
            output.writeInt( unmodifiableCollection.ordinal(), true );
            kryo.writeClassAndObject( output, unmodifiableCollection.sourceCollectionField.get( object ) );
        } catch ( final RuntimeException e ) {
            // Don't eat and wrap RuntimeExceptions because the ObjectBuffer.write...
            // handles SerializationException specifically (resizing the buffer)...
            throw e;
        } catch ( final Exception e ) {
            throw new RuntimeException( e );
        }
    }

    @Override
    public Object copy(Kryo kryo, Object original) {
      try {
          final UnmodifiableCollection unmodifiableCollection = UnmodifiableCollection.valueOfType( original.getClass() );
          Object sourceCollectionCopy = kryo.copy(unmodifiableCollection.sourceCollectionField.get(original));
          return unmodifiableCollection.create( sourceCollectionCopy );
      } catch ( final RuntimeException e ) {
          // Don't eat and wrap RuntimeExceptions
          throw e;
      } catch ( final Exception e ) {
          throw new RuntimeException( e );
      }
    }

    private static enum UnmodifiableCollection {
        COLLECTION( Collections.unmodifiableCollection( Arrays.asList( "" ) ).getClass(), SOURCE_COLLECTION_FIELD ){
            @Override
            public Object create( final Object sourceCollection ) {
                return Collections.unmodifiableCollection( (Collection<?>) sourceCollection );
            }
        },
        RANDOM_ACCESS_LIST( Collections.unmodifiableList( new ArrayList<Void>() ).getClass(), SOURCE_COLLECTION_FIELD ){
            @Override
            public Object create( final Object sourceCollection ) {
                return Collections.unmodifiableList( (List<?>) sourceCollection );
            }
        },
        LIST( Collections.unmodifiableList( new LinkedList<Void>() ).getClass(), SOURCE_COLLECTION_FIELD ){
            @Override
            public Object create( final Object sourceCollection ) {
                return Collections.unmodifiableList( (List<?>) sourceCollection );
            }
        },
        SET( Collections.unmodifiableSet( new HashSet<Void>() ).getClass(), SOURCE_COLLECTION_FIELD ){
            @Override
            public Object create( final Object sourceCollection ) {
                return Collections.unmodifiableSet( (Set<?>) sourceCollection );
            }
        },
        SORTED_SET( Collections.unmodifiableSortedSet( new TreeSet<Void>() ).getClass(), SOURCE_COLLECTION_FIELD ){
            @Override
            public Object create( final Object sourceCollection ) {
                return Collections.unmodifiableSortedSet( (SortedSet<?>) sourceCollection );
            }
        },
        MAP( Collections.unmodifiableMap( new HashMap<Void, Void>() ).getClass(), SOURCE_MAP_FIELD ) {

            @Override
            public Object create( final Object sourceCollection ) {
                return Collections.unmodifiableMap( (Map<?, ?>) sourceCollection );
            }

        },
        SORTED_MAP( Collections.unmodifiableSortedMap( new TreeMap<Void, Void>() ).getClass(), SOURCE_MAP_FIELD ) {
            @Override
            public Object create( final Object sourceCollection ) {
                return Collections.unmodifiableSortedMap( (SortedMap<?, ?>) sourceCollection );
            }
        };

        private final Class<?> type;
        private final Field sourceCollectionField;

        private UnmodifiableCollection( final Class<?> type, final Field sourceCollectionField ) {
            this.type = type;
            this.sourceCollectionField = sourceCollectionField;
        }

        /**
         * @param sourceCollection
         */
        public abstract Object create( Object sourceCollection );

        static UnmodifiableCollection valueOfType( final Class<?> type ) {
            for( final UnmodifiableCollection item : values() ) {
                if ( item.type.equals( type ) ) {
                    return item;
                }
            }
            throw new IllegalArgumentException( "The type " + type + " is not supported." );
        }

    }

    /**
     * Creates a new {@link UnmodifiableCollectionsSerializer} and registers its serializer
     * for the several unmodifiable Collections that can be created via {@link Collections},
     * including {@link Map}s.
     *
     * @param kryo the {@link Kryo} instance to set the serializer on.
     *
     * @see Collections#unmodifiableCollection(Collection)
     * @see Collections#unmodifiableList(List)
     * @see Collections#unmodifiableSet(Set)
     * @see Collections#unmodifiableSortedSet(SortedSet)
     * @see Collections#unmodifiableMap(Map)
     * @see Collections#unmodifiableSortedMap(SortedMap)
     */
    public static void registerSerializers( final Kryo kryo ) {
        final UnmodifiableCollectionsSerializer serializer = new UnmodifiableCollectionsSerializer();
        UnmodifiableCollection.values();
        for ( final UnmodifiableCollection item : UnmodifiableCollection.values() ) {
            kryo.register( item.type, serializer );
        }
    }

}


package de.javakaffee.kryoserializers.guava;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Lists;
import com.google.common.collect.Table;

/**
 * A kryo {@link Serializer} for guava-libraries {@link ImmutableList}.
 */
public class ImmutableListSerializer extends Serializer<ImmutableList<Object>> {

    private static final boolean DOES_NOT_ACCEPT_NULL = false;
    private static final boolean IMMUTABLE = true;

    public ImmutableListSerializer() {
        super(DOES_NOT_ACCEPT_NULL, IMMUTABLE);
    }

    @Override
    public void write(Kryo kryo, Output output, ImmutableList<Object> object) {
        output.writeInt(object.size(), true);
        for (Object elm : object) {
            kryo.writeClassAndObject(output, elm);
        }
    }

    @Override
    public ImmutableList<Object> read(Kryo kryo, Input input, Class<? extends ImmutableList<Object>> type) {
        final int size = input.readInt(true);
        final Object[] list = new Object[size];
        for (int i = 0; i < size; ++i) {
            list[i] = kryo.readClassAndObject(input);
        }
        return ImmutableList.copyOf(list);
    }

    /**
     * Creates a new {@link ImmutableListSerializer} and registers its serializer
     * for the several ImmutableList related classes.
     *
     * @param kryo the {@link Kryo} instance to set the serializer on
     */
    public static void registerSerializers(final Kryo kryo) {

        // ImmutableList (abstract class)
        //  +- RegularImmutableList
        //  |   RegularImmutableList
        //  +- SingletonImmutableList
        //  |   Optimized for List with only 1 element.
        //  +- SubList
        //  |   Representation for part of ImmutableList
        //  +- ReverseImmutableList
        //  |   For iterating in reverse order
        //  +- StringAsImmutableList
        //  |   Used by Lists#charactersOf
        //  +- Values (ImmutableTable values)
        //      Used by return value of #values() when there are multiple cells

        final ImmutableListSerializer serializer = new ImmutableListSerializer();

        kryo.register(ImmutableList.class, serializer);

        // Note:
        //  Only registering above is good enough for serializing/deserializing.
        //  but if using Kryo#copy, following is required.

        kryo.register(ImmutableList.of().getClass(), serializer);
        kryo.register(ImmutableList.of(1).getClass(), serializer);
        kryo.register(ImmutableList.of(1, 2, 3, 4).subList(1, 3).getClass(), serializer);
        kryo.register(ImmutableList.of(1, 2).reverse().getClass(), serializer);

        kryo.register(Lists.charactersOf("KryoRocks").getClass(), serializer);

        Table<Integer,Integer,Integer> baseTable = HashBasedTable.create();
        baseTable.put(1, 2, 3);
        baseTable.put(4, 5, 6);
        Table<Integer, Integer, Integer> table = ImmutableTable.copyOf(baseTable);
        kryo.register(table.values().getClass(), serializer);

    }
}


package de.javakaffee.kryoserializers.dexx;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;

import com.github.andrewoma.dexx.collection.Builder;
import com.github.andrewoma.dexx.collection.Set;
import com.github.andrewoma.dexx.collection.Sets;

/**
* A kryo {@link Serializer} for dexx {@link Set}
 */
public class SetSerializer extends Serializer<Set<Object>> {

    private static final boolean DOES_NOT_ACCEPT_NULL = false;
    private static final boolean IMMUTABLE = true;

    public SetSerializer() {
        super(DOES_NOT_ACCEPT_NULL, IMMUTABLE);
    }

    @Override
    public void write(Kryo kryo, Output output, Set<Object> object) {
        output.writeInt(object.size(), true);
        for (Object elm : object) {
            kryo.writeClassAndObject(output, elm);
        }
    }

    @Override
    public Set<Object> read(Kryo kryo, Input input, Class<? extends Set<Object>> type) {
        final int size = input.readInt(true);
        Builder<Object, Set<Object>> builder = Sets.builder();
        for (int i = 0; i < size; ++i) {
            builder.add(kryo.readClassAndObject(input));
        }
        return builder.build();
    }

    /**
     * Creates a new {@link ImmutableSetSerializer} and registers its serializer
     * for the several ImmutableSet related classes.
     *
     * @param kryo the {@link Kryo} instance to set the serializer on
     */
    public static void registerSerializers(final Kryo kryo) {

        final SetSerializer serializer = new SetSerializer();

        kryo.register(Set.class, serializer);

        // Note:
        //  Only registering above is good enough for serializing/deserializing.
        //  but if using Kryo#copy, following is required.

        kryo.register(Sets.of().getClass(), serializer);
        kryo.register(Sets.of(1).getClass(), serializer);
        kryo.register(Sets.of(1,2,3).getClass(), serializer);
        kryo.register(Sets.of(1,2,3,4).getClass(), serializer);
        kryo.register(Sets.of(1,2,3,4,5).getClass(), serializer);
        kryo.register(Sets.of(1,2,3,4,5,6).getClass(), serializer);
        kryo.register(Sets.of(1,2,3,4,5,6,7).getClass(), serializer);
        kryo.register(Sets.of(1,2,3,4,5,6,7,8).getClass(), serializer);
        kryo.register(Sets.of(1,2,3,4,5,6,7,8,9).getClass(), serializer);
        kryo.register(Sets.of(1,2,3,4,5,6,7,8,9,10).getClass(), serializer);
        kryo.register(Sets.of(1,2,3,4,5,6,7,8,9,10,11).getClass(), serializer);

    }
}


/*
 * Copyright 2010 Martin Grotzke
 *
 * 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 de.javakaffee.kryoserializers;

import java.lang.reflect.Constructor;
import java.util.Date;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;

/**
 * A kryo {@link Serializer} for {@link Date} and subclasses. Must be registered like this:
 *

 *  Kryo kryo = new Kryo() {
 *      public Serializer<?> getDefaultSerializer(final Class clazz) {
 *          if ( Date.class.isAssignableFrom( type ) ) {
 *              return new DateSerializer( type );
 *          }
 *          return super.getDefaultSerializer( clazz );
 *      }
 *  };
 *

 *
 * @author Martin Grotzke
 */
public class DateSerializer extends Serializer<Date> {

    private final Constructor<? extends Date> _constructor;

    public DateSerializer(final Class<? extends Date> clazz) {
        try {
            _constructor = clazz.getConstructor(long.class);
        } catch ( final Exception e ) {
            throw new RuntimeException( e );
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Date read(final Kryo kryo, final Input input, final Class<? extends Date> type) {
        try {
            return _constructor.newInstance(input.readLong(true));
        } catch (final Exception e) {
            throw new RuntimeException( e );
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void write(final Kryo kryo, final Output output, final Date obj) {
        output.writeLong(obj.getTime(), true);
    }

    @Override
    public Date copy(final Kryo kryo, final Date original) {
        return (Date) original.clone();
    }

}


package de.javakaffee.kryoserializers.guava;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;

/**
 * A kryo {@link Serializer} for guava-libraries {@link LinkedHashMultimap}.
 */
public class LinkedHashMultimapSerializer extends MultimapSerializerBase<Object, Object, LinkedHashMultimap<Object, Object>> {

    private static final boolean DOES_NOT_ACCEPT_NULL = false;

    private static final boolean IMMUTABLE = false;

    public LinkedHashMultimapSerializer() {
        super(DOES_NOT_ACCEPT_NULL, IMMUTABLE);
    }

    @Override
    public void write(Kryo kryo, Output output, LinkedHashMultimap<Object, Object> multimap) {
        writeMultimap(kryo, output, multimap);
    }

    @Override
    public LinkedHashMultimap<Object, Object> read(Kryo kryo, Input input, Class<? extends LinkedHashMultimap<Object, Object>> type) {
        final LinkedHashMultimap<Object, Object> multimap = LinkedHashMultimap.create();
        readMultimap(kryo, input, multimap);
        return multimap;
    }

    @Override
    protected Multimap createCopy(Kryo kryo, Multimap original) {
        return LinkedHashMultimap.create();
    }

    /**
     * Creates a new {@link LinkedHashMultimapSerializer} and registers its serializer.
     *
     * @param kryo the {@link Kryo} instance to set the serializer on
     */
    public static void registerSerializers(final Kryo kryo) {
        final LinkedHashMultimapSerializer serializer = new LinkedHashMultimapSerializer();
        kryo.register(LinkedHashMultimap.class, serializer);
    }
}


package de.javakaffee.kryoserializers.guava;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.google.common.collect.ImmutableTable;

/**
 * A kryo {@link Serializer} for guava-libraries {@link ImmutableTable}.
 */
public class ImmutableTableSerializer<R, C, V> extends TableSerializerBase<R, C, V, ImmutableTable<R, C, V>> {

    private static final boolean HANDLES_NULL = false;
    private static final boolean IMMUTABLE = true;

    public ImmutableTableSerializer() {
        super(HANDLES_NULL, IMMUTABLE);
    }

    @Override
    public void write(Kryo kryo, Output output, ImmutableTable<R, C, V> immutableTable) {
        super.writeTable(kryo, output, immutableTable);
    }

    @Override
    public ImmutableTable<R, C, V> read(Kryo kryo, Input input, Class<? extends ImmutableTable<R, C, V>> type) {
        final ImmutableTable.Builder<R, C, V> builder = ImmutableTable.builder();
        super.readTable(kryo, input, new CellConsumer<R, C, V>() {
            @Override
            public void accept(R r, C c, V v) {
                builder.put(r, c, v);
            }
        });
        return builder.build();
    }

    /**
     * Creates a new {@link ImmutableTableSerializer} and registers its serializer.
     *
     * @param kryo the {@link Kryo} instance to set the serializer on
     */
    public static void registerSerializers(final Kryo kryo) {

        // ImmutableTable (abstract class)
        //  +- SparseImmutableTable
        //  |   SparseImmutableTable
        //  +- DenseImmutableTable
        //  |   Used when more than half of the cells have values
        //  +- SingletonImmutableTable
        //  |   Optimized for Table with only 1 element.

        final ImmutableTableSerializer serializer = new ImmutableTableSerializer();

        kryo.register(ImmutableTable.class, serializer); // ImmutableTable
        kryo.register(ImmutableTable.of().getClass(), serializer); // SparseImmutableTable
        kryo.register(ImmutableTable.of(1, 2, 3).getClass(), serializer);  // SingletonImmutableTable

        kryo.register(ImmutableTable.builder()
                .put("a", 1, 1)
                .put("b", 1, 1)
                .build().getClass(), serializer); // DenseImmutableTable

    }
}


package de.javakaffee.kryoserializers.protobuf;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.google.protobuf.AbstractMessage;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static com.esotericsoftware.kryo.Kryo.NULL;

public class ProtobufSerializer<T extends AbstractMessage> extends Serializer<T> {

    private Method parseFromMethod = null;

    @Override
    public void write(Kryo kryo, Output output, T protobufMessage) {
        // If our protobuf is null
        if (protobufMessage == null) {
            // Write our special null value
            output.writeByte(NULL);
            output.flush();

            // and we're done
            return;
        }

        // Otherwise serialize protobuf to a byteArray
        byte[] bytes = protobufMessage.toByteArray();

        // Write the length of our byte array
        output.writeInt(bytes.length + 1, true);

        // Write the byte array out
        output.writeBytes(bytes);
        output.flush();
    }

    @Override
    public T read(Kryo kryo, Input input, Class<? extends T> type) {
        // Read the length of our byte array
        int length = input.readInt(true);

        // If the length is equal to our special null value
        if (length == NULL) {
            // Just return null
            return null;
        }
        // Otherwise read the byte array length
        byte[] bytes = input.readBytes(length - 1);
        try {
            // Deserialize protobuf
            return (T) (getParseFromMethod(type).invoke(type, bytes));
        } catch (NoSuchMethodException e) {
            throw new RuntimeException("Unable to deserialize protobuf "+e.getMessage(), e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException("Unable to deserialize protobuf "+e.getMessage(), e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Unable to deserialize protobuf "+e.getMessage(), e);
        }
    }

    /**
     * Caches method reflection lookup
     * @throws NoSuchMethodException
     */
    private Method getParseFromMethod(Class<? extends T> type) throws NoSuchMethodException {
        if (parseFromMethod == null) {
            parseFromMethod = type.getMethod("parseFrom", byte[].class);
        }
        return parseFromMethod;
    }

    @Override
    public boolean getAcceptsNull () {
        return true;
    }
}


package de.javakaffee.kryoserializers.guava;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

/**
 * A kryo {@link Serializer} for guava-libraries {@link ArrayListMultimap}.
 */
public class ArrayListMultimapSerializer extends MultimapSerializerBase<Object, Object, ArrayListMultimap<Object, Object>> {

    private static final boolean DOES_NOT_ACCEPT_NULL = false;

    private static final boolean IMMUTABLE = false;

    public ArrayListMultimapSerializer() {
        super(DOES_NOT_ACCEPT_NULL, IMMUTABLE);
    }

    @Override
    public void write(Kryo kryo, Output output, ArrayListMultimap<Object, Object> multimap) {
        writeMultimap(kryo, output, multimap);
    }

    @Override
    public ArrayListMultimap<Object, Object> read(Kryo kryo, Input input, Class<? extends ArrayListMultimap<Object, Object>> type) {
        final ArrayListMultimap<Object, Object> multimap = ArrayListMultimap.create();
        readMultimap(kryo, input, multimap);
        return multimap;
    }

    @Override
    protected Multimap createCopy(Kryo kryo, Multimap original) {
        return ArrayListMultimap.create();
    }

    /**
     * Creates a new {@link ArrayListMultimapSerializer} and registers its serializer.
     *
     * @param kryo the {@link Kryo} instance to set the serializer on
     */
    public static void registerSerializers(final Kryo kryo) {
        final ArrayListMultimapSerializer serializer = new ArrayListMultimapSerializer();
        kryo.register(ArrayListMultimap.class, serializer);
    }
}


package de.javakaffee.kryoserializers.guava;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;

/**
 * A kryo {@link Serializer} for guava-libraries {@link LinkedListMultimap}.
 */
public class LinkedListMultimapSerializer extends MultimapSerializerBase<Object, Object, LinkedListMultimap<Object, Object>> {

    private static final boolean DOES_NOT_ACCEPT_NULL = false;

    private static final boolean IMMUTABLE = false;

    public LinkedListMultimapSerializer() {
        super(DOES_NOT_ACCEPT_NULL, IMMUTABLE);
    }

    @Override
    public void write(Kryo kryo, Output output, LinkedListMultimap<Object, Object> multimap) {
        writeMultimap(kryo, output, multimap);
    }

    @Override
    public LinkedListMultimap<Object, Object> read(Kryo kryo, Input input, Class<? extends LinkedListMultimap<Object, Object>> type) {
        final LinkedListMultimap<Object, Object> multimap = LinkedListMultimap.create();
        readMultimap(kryo, input, multimap);
        return multimap;
    }

    @Override
    protected Multimap createCopy(Kryo kryo, Multimap original) {
        return LinkedListMultimap.create(original.keySet().size());
    }

    /**
     * Creates a new {@link LinkedListMultimapSerializer} and registers its serializer.
     *
     * @param kryo the {@link Kryo} instance to set the serializer on
     */
    public static void registerSerializers(final Kryo kryo) {
        final LinkedListMultimapSerializer serializer = new LinkedListMultimapSerializer();
        kryo.register(LinkedListMultimap.class, serializer);
    }
}