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

org.echocat.jomon.runtime.io.Serializers Maven / Gradle / Ivy

/*****************************************************************************************
 * *** BEGIN LICENSE BLOCK *****
 *
 * Version: MPL 2.0
 *
 * echocat Jomon, Copyright (c) 2012-2013 echocat
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * *** END LICENSE BLOCK *****
 ****************************************************************************************/

package org.echocat.jomon.runtime.io;

import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.ThreadSafe;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.WeakHashMap;

import static java.nio.charset.Charset.defaultCharset;
import static org.echocat.jomon.runtime.CollectionUtils.asMap;
import static org.echocat.jomon.runtime.io.ByteUtils.*;

public class Serializers {

    @Nonnull
    private static final ChunkAwareSerializer BOOLEAN_SERIALIZER = new BooleanSerializer();
    @Nonnull
    private static final ChunkAwareSerializer BYTE_SERIALIZER = new ByteSerializer();
    @Nonnull
    private static final ChunkAwareSerializer SHORT_SERIALIZER = new ShortSerializer();
    @Nonnull
    private static final ChunkAwareSerializer INTEGER_SERIALIZER = new IntegerSerializer();
    @Nonnull
    private static final ChunkAwareSerializer LONG_SERIALIZER = new LongSerializer();
    @Nonnull
    private static final ChunkAwareSerializer FLOAT_SERIALIZER = new FloatSerializer();
    @Nonnull
    private static final ChunkAwareSerializer DOUBLE_SERIALIZER = new DoubleSerializer();
    @Nonnull
    private static final Serializer STRING_SERIALIZER = new StringSerializer();
    @Nonnull
    private static final Map, Serializer> TYPE_TO_SERIALIZER_CACHE = new WeakHashMap<>();

    @Nonnull
    private static final Map, ChunkAwareSerializer> TYPE_TO_CHUNK_AWARE_SERIALIZER = asMap(
        Boolean.class, BOOLEAN_SERIALIZER,
        boolean.class, BOOLEAN_SERIALIZER,
        Byte.class, BYTE_SERIALIZER,
        byte.class, BYTE_SERIALIZER,
        Short.class, SHORT_SERIALIZER,
        short.class, SHORT_SERIALIZER,
        Integer.class, INTEGER_SERIALIZER,
        int.class, INTEGER_SERIALIZER,
        Long.class, LONG_SERIALIZER,
        long.class, LONG_SERIALIZER,
        Float.class, FLOAT_SERIALIZER,
        float.class, FLOAT_SERIALIZER,
        Double.class, DOUBLE_SERIALIZER,
        double.class, DOUBLE_SERIALIZER
    );

    @Nonnull
    private static final Map, Serializer> TYPE_TO_SERIALIZER = asMap(
        Boolean.class, BOOLEAN_SERIALIZER,
        boolean.class, BOOLEAN_SERIALIZER,
        Byte.class, BYTE_SERIALIZER,
        byte.class, BYTE_SERIALIZER,
        Short.class, SHORT_SERIALIZER,
        short.class, SHORT_SERIALIZER,
        Integer.class, INTEGER_SERIALIZER,
        int.class, INTEGER_SERIALIZER,
        Long.class, LONG_SERIALIZER,
        long.class, LONG_SERIALIZER,
        Float.class, FLOAT_SERIALIZER,
        float.class, FLOAT_SERIALIZER,
        Double.class, DOUBLE_SERIALIZER,
        double.class, DOUBLE_SERIALIZER,
        String.class, STRING_SERIALIZER
    );

    @Nonnull
    public static ChunkAwareSerializer booleanSerializer() {
        return BOOLEAN_SERIALIZER;
    }

    @Nonnull
    public static ChunkAwareSerializer byteSerializer() {
        return BYTE_SERIALIZER;
    }

    @Nonnull
    public static ChunkAwareSerializer shortSerializer() {
        return SHORT_SERIALIZER;
    }

    @Nonnull
    public static ChunkAwareSerializer integerSerializer() {
        return INTEGER_SERIALIZER;
    }

    @Nonnull
    public static ChunkAwareSerializer longSerializer() {
        return LONG_SERIALIZER;
    }

    @Nonnull
    public static ChunkAwareSerializer floatSerializer() {
        return FLOAT_SERIALIZER;
    }

    @Nonnull
    public static ChunkAwareSerializer doubleSerializer() {
        return DOUBLE_SERIALIZER;
    }

    @Nonnull
    public static Serializer stringSerializer() {
        return STRING_SERIALIZER;
    }

    @Nonnull
    public static ChunkAwareSerializer stringSerializer(@Nonnegative int bufferSize, @Nonnull Charset charset) {
        return new ChunkAwareStringSerializer(bufferSize, charset);
    }

    @Nonnull
    public static ChunkAwareSerializer stringSerializer(@Nonnegative int bufferSize) {
        return stringSerializer(bufferSize, defaultCharset());
    }

    /**
     * @return size of the chunk for given type.
     * @throws IllegalArgumentException if there is no {@link org.echocat.jomon.runtime.io.ChunkAwareSerializer} available for given type.
     * In this case the type was not annotated with {@link org.echocat.jomon.runtime.io.SerializableBy}.
     */
    @Nonnegative
    public static int getChunkSizeOf(@Nonnull Class type) throws IllegalArgumentException {
        final ChunkAwareSerializer serializer = getChunkAwareSerializerOf(type);
        return serializer.getChunkSize();
    }

    /**
     * @return null if there is no {@link org.echocat.jomon.runtime.io.Serializer} available for given type. In this case
     * the type was not annotated with {@link org.echocat.jomon.runtime.io.SerializableBy}. Otherwise the chunk size for the given type.
     */
    @Nullable
    @Nonnegative
    public static Integer findChunkSizeOf(@Nonnull Class type) {
        final ChunkAwareSerializer serializer = findChunkAwareSerializerOf(type);
        return serializer != null ? serializer.getChunkSize() : null;
    }

    /**
     * @throws IllegalArgumentException if there is no {@link org.echocat.jomon.runtime.io.ChunkAwareSerializer} available for given type.
     * In this case the type was not annotated with {@link org.echocat.jomon.runtime.io.SerializableBy}.
     */
    @Nonnull
    public static  ChunkAwareSerializer getChunkAwareSerializerOf(@Nonnull Class type) throws IllegalArgumentException {
        final ChunkAwareSerializer result = findChunkAwareSerializerOf(type);
        if (result == null) {
            throw new IllegalArgumentException("There is no serializer available for " + type.getName() + ".");
        }
        return result;
    }

    /**
     * @throws IllegalArgumentException if there is no {@link org.echocat.jomon.runtime.io.Serializer} available for given type.
     * In this case the type was not annotated with {@link org.echocat.jomon.runtime.io.SerializableBy}.
     */
    @Nonnull
    public static  Serializer getSerializerOf(@Nonnull Class type) throws IllegalArgumentException {
        final Serializer result = findSerializerOf(type);
        if (result == null) {
            throw new IllegalArgumentException("There is no serializer available for " + type.getName() + ".");
        }
        return result;
    }

    /**
     * @return null if there is no {@link org.echocat.jomon.runtime.io.Serializer} available for given type. In this case
     * the type was not annotated with {@link org.echocat.jomon.runtime.io.SerializableBy}.
     */
    @Nullable
    public static  Serializer findSerializerOf(@Nonnull Class type) {
        Serializer result = TYPE_TO_SERIALIZER.get(type);
        if (result == null) {
            synchronized (TYPE_TO_SERIALIZER_CACHE) {
                result = TYPE_TO_SERIALIZER_CACHE.get(type);
                if (result == null) {
                    final Class> serializerType = findSerializerTypeOf(type);
                    if (serializerType != null) {
                        try {
                            result = serializerType.newInstance();
                        } catch (final Exception e) {
                            throw new RuntimeException("Could not create an instance of " + serializerType.getName() + " to serialize " + type.getName() + ".", e);
                        }
                        TYPE_TO_SERIALIZER_CACHE.put(type, result);
                    } else {
                        result = null;
                    }
                }
            }
        }
        // noinspection unchecked
        return (Serializer) result;
    }

    /**
     * @return null if there is no {@link org.echocat.jomon.runtime.io.ChunkAwareSerializer} available for given type. In this case
     * the type was not annotated with {@link org.echocat.jomon.runtime.io.SerializableBy}.
     */
    @Nullable
    public static  ChunkAwareSerializer findChunkAwareSerializerOf(@Nonnull Class type) {
        ChunkAwareSerializer result = TYPE_TO_CHUNK_AWARE_SERIALIZER.get(type);
        if (result == null) {
            final Serializer serializer = findSerializerOf(type);
            result = serializer instanceof ChunkAwareSerializer ? (ChunkAwareSerializer) serializer : null;
        }
        // noinspection unchecked
        return (ChunkAwareSerializer) result;
    }

    /**
     * @return null if there is no {@link org.echocat.jomon.runtime.io.Serializer} available for given type. In this case
     * the type was not annotated with {@link org.echocat.jomon.runtime.io.SerializableBy}.
     */
    @Nullable
    public static  Class> findSerializerTypeOf(@Nonnull Class type) {
        final SerializableBy annotation = type.getAnnotation(SerializableBy.class);
        // noinspection unchecked
        return annotation != null ? (Class) annotation.value() : null;
    }

    @ThreadSafe
    @Immutable
    public static class BooleanSerializer implements ChunkAwareSerializer {
        @Override public int getChunkSize() { return BOOLEAN_CHUNK_SIZE; }
        @Nonnull @Override public Boolean read(@Nonnull DataInput from) throws IOException { return from.readBoolean(); }
        @Override public void write(@Nonnull Boolean value, @Nonnull DataOutput to) throws IOException { to.writeBoolean(value); }
    }

    @ThreadSafe
    @Immutable
    public static class ByteSerializer implements ChunkAwareSerializer {
        @Override public int getChunkSize() { return BYTE_CHUNK_SIZE; }
        @Nonnull @Override public Byte read(@Nonnull DataInput from) throws IOException { return from.readByte(); }
        @Override public void write(@Nonnull Byte value, @Nonnull DataOutput to) throws IOException { to.writeByte(value); }
    }

    @ThreadSafe
    @Immutable
    public static class ShortSerializer implements ChunkAwareSerializer {
        @Override public int getChunkSize() { return SHORT_CHUNK_SIZE; }
        @Nonnull @Override public Short read(@Nonnull DataInput from) throws IOException { return from.readShort(); }
        @Override public void write(@Nonnull Short value, @Nonnull DataOutput to) throws IOException { to.writeShort(value); }
    }

    @ThreadSafe
    @Immutable
    public static class IntegerSerializer implements ChunkAwareSerializer {
        @Override public int getChunkSize() { return INTEGER_CHUNK_SIZE; }
        @Nonnull @Override public Integer read(@Nonnull DataInput from) throws IOException { return from.readInt(); }
        @Override public void write(@Nonnull Integer value, @Nonnull DataOutput to) throws IOException { to.writeInt(value); }
    }

    @ThreadSafe
    @Immutable
    public static class LongSerializer implements ChunkAwareSerializer {
        @Override public int getChunkSize() { return LONG_CHUNK_SIZE; }
        @Nonnull @Override public Long read(@Nonnull DataInput from) throws IOException { return from.readLong(); }
        @Override public void write(@Nonnull Long value, @Nonnull DataOutput to) throws IOException { to.writeLong(value); }
    }

    @ThreadSafe
    @Immutable
    public static class FloatSerializer implements ChunkAwareSerializer {
        @Override public int getChunkSize() { return FLOAT_CHUNK_SIZE; }
        @Nonnull @Override public Float read(@Nonnull DataInput from) throws IOException { return from.readFloat(); }
        @Override public void write(@Nonnull Float value, @Nonnull DataOutput to) throws IOException { to.writeFloat(value); }
    }

    @ThreadSafe
    @Immutable
    public static class DoubleSerializer implements ChunkAwareSerializer {
        @Override public int getChunkSize() { return DOUBLE_CHUNK_SIZE; }
        @Nonnull @Override public Double read(@Nonnull DataInput from) throws IOException { return from.readDouble(); }
        @Override public void write(@Nonnull Double value, @Nonnull DataOutput to) throws IOException { to.writeDouble(value); }
    }

    @ThreadSafe
    @Immutable
    public static class ChunkAwareStringSerializer implements ChunkAwareSerializer {

        @Nonnull
        private final Charset _charset;
        @Nonnegative
        private final int _bufferSize;
        @Nonnegative
        private final int _chunkSize;

        public ChunkAwareStringSerializer(@Nonnegative int bufferSize, @Nonnull Charset charset) {
            _bufferSize = bufferSize;
            _charset = charset;
            _chunkSize = getStringChunkSizeFor(bufferSize);
        }

        @Override
        public int getChunkSize() {
            return _chunkSize;
        }

        @Nullable
        @Override
        public String read(@Nonnull DataInput from) throws IOException {
            final byte[] buffer = new byte[_chunkSize];
            from.readFully(buffer);
            return getString(buffer, _bufferSize, 0, _charset);
        }

        @Override
        public void write(@Nullable String value, @Nonnull DataOutput to) throws IOException {
            final byte[] buffer = new byte[_chunkSize];
            putString(buffer, _bufferSize, 0, value, _charset);
            to.write(buffer);
        }

    }

    @ThreadSafe
    @Immutable
    public static class StringSerializer implements Serializer {

        @Nullable
        @Override
        public String read(@Nonnull DataInput from) throws IOException {
            return from.readUTF();
        }

        @Override
        public void write(@Nullable String value, @Nonnull DataOutput to) throws IOException {
            to.writeUTF(value);
        }

    }

    private Serializers() {}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy