/*
* Copyright 2015 MiLaboratory.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.milaboratory.primitivio;
import java.lang.reflect.Array;
import java.util.UUID;
public class DefaultSerializersProviderImpl implements DefaultSerializersProvider {
@Override
public Serializer createSerializer(Class<?> type, SerializersManager manager) {
if (type.isArray()) {
Class<?> componentType = type.getComponentType();
if (componentType.isPrimitive()) {
if (componentType == Integer.TYPE)
return new IntArraySerializer();
else if (componentType == Byte.TYPE)
return new ByteArraySerializer();
else if (componentType == Boolean.TYPE)
return new BooleanArraySerializer();
else
return null;
} else {
return new ArraySerializer(manager.getSerializer(componentType) == null ? null : componentType);
}
}
if (type.isEnum())
return new EnumSerializer(type);
if (type == Integer.class)
return new IntegerSerializer();
if (type == UUID.class)
return new UUIDSerializer();
if (type == String.class)
return new StringSerializer();
return null;
}
private static class IntegerSerializer implements Serializer<Integer> {
@Override
public void write(PrimitivO output, Integer object) {
output.writeInt(object);
}
@Override
public Integer read(PrimitivI input) {
return input.readInt();
}
@Override
public boolean isReference() {
return false;
}
@Override
public boolean handlesReference() {
return false;
}
}
private static class StringSerializer implements Serializer<String> {
@Override
public void write(PrimitivO output, String object) {
output.writeUTF(object);
}
@Override
public String read(PrimitivI input) {
return input.readUTF();
}
@Override
public boolean isReference() {
return false;
}
@Override
public boolean handlesReference() {
return false;
}
}
private static class IntArraySerializer implements Serializer<int[]> {
@Override
public void write(PrimitivO output, int[] object) {
output.writeVarInt(object.length);
for (int i : object)
output.writeInt(i);
}
@Override
public int[] read(PrimitivI input) {
int[] object = new int[input.readVarInt()];
for (int i = 0; i < object.length; i++)
object[i] = input.readInt();
return object;
}
@Override
public boolean isReference() {
return true;
}
@Override
public boolean handlesReference() {
return false;
}
}
private static class ByteArraySerializer implements Serializer<byte[]> {
@Override
public void write(PrimitivO output, byte[] object) {
output.writeVarInt(object.length);
output.write(object);
}
@Override
public byte[] read(PrimitivI input) {
byte[] object = new byte[input.readVarInt()];
input.readFully(object);
return object;
}
@Override
public boolean isReference() {
return false;
}
@Override
public boolean handlesReference() {
return false;
}
}
private static class BooleanArraySerializer implements Serializer<boolean[]> {
@Override
public void write(PrimitivO output, boolean[] object) {
output.writeVarInt(object.length);
for (int i = 0; i < object.length; ++i)
output.writeBoolean(object[i]);
}
@Override
public boolean[] read(PrimitivI input) {
boolean[] object = new boolean[input.readVarInt()];
for (int i = 0; i < object.length; ++i)
object[i] = input.readBoolean();
return object;
}
@Override
public boolean isReference() {
return false;
}
@Override
public boolean handlesReference() {
return false;
}
}
private static class EnumSerializer implements Serializer {
final Class<?> enumType;
final Object[] array;
private EnumSerializer(Class<?> enumType) {
this.enumType = enumType;
this.array = new Object[enumType.getEnumConstants().length];
System.arraycopy(enumType.getEnumConstants(), 0, array, 0, array.length);
}
@Override
public void write(PrimitivO output, Object object) {
Enum e = (Enum) object;
output.writeVarInt(e.ordinal());
}
@Override
public Object read(PrimitivI input) {
return array[input.readVarInt()];
}
@Override
public boolean isReference() {
return false;
}
@Override
public boolean handlesReference() {
return false;
}
}
/**
* For Compatibility with previous format
*/
public static final class CustomEnumSerializer<E extends Enum<E>> implements Serializer {
final Class<E> enumType;
final E[] array;
public CustomEnumSerializer(Class<E> enumType, E... valuesByOrdinal) {
this.enumType = enumType;
this.array = valuesByOrdinal;
}
@Override
public void write(PrimitivO output, Object object) {
throw new IllegalStateException("Not implemented.");
}
@Override
public Object read(PrimitivI input) {
return array[input.readVarInt()];
}
@Override
public boolean isReference() {
return false;
}
@Override
public boolean handlesReference() {
return false;
}
}
private static class UUIDSerializer implements Serializer<UUID> {
@Override
public void write(PrimitivO output, UUID object) {
output.writeLong(object.getMostSignificantBits());
output.writeLong(object.getLeastSignificantBits());
}
@Override
public UUID read(PrimitivI input) {
long msb = input.readLong();
long lsb = input.readLong();
return new UUID(msb, lsb);
}
@Override
public boolean isReference() {
return false;
}
@Override
public boolean handlesReference() {
return false;
}
}
private static class ArraySerializer implements Serializer {
final Class<?> componentType;
private ArraySerializer(Class<?> componentType) {
this.componentType = componentType;
}
@Override
public void write(PrimitivO output, Object object) {
int length = Array.getLength(object);
output.writeVarInt(length);
for (int i = 0; i < length; i++) {
if (componentType == null)
output.writeObject(Array.get(object, i));
else
output.writeObject(Array.get(object, i), componentType);
}
}
@Override
public Object read(PrimitivI input) {
int length = input.readVarInt();
if (componentType == null)
throw new RuntimeException("Unknown array type.");
Object array = Array.newInstance(componentType, length);
for (int i = 0; i < length; i++)
Array.set(array, i, input.readObject(componentType));
return array;
}
@Override
public boolean isReference() {
return true;
}
@Override
public boolean handlesReference() {
return false;
}
}
}