Package info.archinnov.achilles.internal.metadata.parsing

Source Code of info.archinnov.achilles.internal.metadata.parsing.CodecFactory

package info.archinnov.achilles.internal.metadata.parsing;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import info.archinnov.achilles.annotations.Enumerated;
import info.archinnov.achilles.annotations.TypeTransformer;
import info.archinnov.achilles.codec.Codec;
import info.archinnov.achilles.internal.metadata.codec.ByteArrayCodec;
import info.archinnov.achilles.internal.metadata.codec.ByteArrayPrimitiveCodec;
import info.archinnov.achilles.internal.metadata.codec.ByteCodec;
import info.archinnov.achilles.internal.metadata.codec.EnumNameCodec;
import info.archinnov.achilles.internal.metadata.codec.EnumOrdinalCodec;
import info.archinnov.achilles.internal.metadata.codec.JSONCodec;
import info.archinnov.achilles.internal.metadata.codec.ListCodec;
import info.archinnov.achilles.internal.metadata.codec.ListCodecImpl;
import info.archinnov.achilles.internal.metadata.codec.MapCodec;
import info.archinnov.achilles.internal.metadata.codec.MapCodecBuilder;
import info.archinnov.achilles.internal.metadata.codec.NativeCodec;
import info.archinnov.achilles.internal.metadata.codec.SetCodec;
import info.archinnov.achilles.internal.metadata.codec.SetCodecImpl;
import info.archinnov.achilles.internal.metadata.holder.InternalTimeUUID;
import info.archinnov.achilles.internal.metadata.parsing.context.PropertyParsingContext;
import info.archinnov.achilles.type.Counter;
import info.archinnov.achilles.type.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

import static com.google.common.base.Optional.fromNullable;
import static info.archinnov.achilles.annotations.Enumerated.Encoding;
import static java.lang.String.format;

public class CodecFactory {

    private static final Logger log = LoggerFactory.getLogger(CodecFactory.class);

    private static final Function<Enumerated, Encoding> keyEncoding = new Function<Enumerated, Encoding>() {
        @Override
        public Encoding apply(Enumerated input) {
            return input.key();
        }
    };

    private static final Function<Enumerated, Encoding> valueEncoding = new Function<Enumerated, Encoding>() {
        @Override
        public Encoding apply(Enumerated input) {
            return input.value();
        }
    };

    protected PropertyFilter filter = PropertyFilter.Singleton.INSTANCE.get();
    protected TypeTransformerParser typeTransformerParser = TypeTransformerParser.Singleton.INSTANCE.get();

    Codec parseSimpleField(PropertyParsingContext context) {
        final Field field = context.getCurrentField();
        log.debug("Parse simple codec for field {}", field);
        final Class type = field.getType();
        if (filter.hasAnnotation(field, TypeTransformer.class)) {
            return typeTransformerParser.parseAndValidateSimpleCodec(field);
        } else {
            final Optional<Encoding> maybeEncoding = fromNullable(field.getAnnotation(Enumerated.class)).transform(valueEncoding);
            return createSimpleCodec(context, type, maybeEncoding);
        }
    }

    ListCodec parseListField(PropertyParsingContext context) {
        final Field field = context.getCurrentField();
        log.debug("Parse list codec for field {}", field);
        if (filter.hasAnnotation(field, TypeTransformer.class)) {
            return typeTransformerParser.parseAndValidateListCodec(field);
        } else {
            final Codec simpleCodec = createSimpleCodecForCollection(context);
            return new ListCodecImpl(simpleCodec.sourceType(), simpleCodec.targetType(), simpleCodec);
        }
    }

    SetCodec parseSetField(PropertyParsingContext context) {
        final Field field = context.getCurrentField();
        log.debug("Parse set codec for field {}", field);
        if (filter.hasAnnotation(field, TypeTransformer.class)) {
            return typeTransformerParser.parseAndValidateSetCodec(field);
        } else {
            final Codec simpleCodec = createSimpleCodecForCollection(context);
            return new SetCodecImpl(simpleCodec.sourceType(), simpleCodec.targetType(), simpleCodec);
        }
    }

    MapCodec parseMapField(PropertyParsingContext context) {
        final Field field = context.getCurrentField();
        log.debug("Parse map codec for field {}", field);

        if (filter.hasAnnotation(field, TypeTransformer.class)) {
            return typeTransformerParser.parseAndValidateMapCodec(field);
        } else {
            final Optional<Encoding> maybeEncodingKey = fromNullable(field.getAnnotation(Enumerated.class)).transform(keyEncoding);
            final Optional<Encoding> maybeEncodingValue = fromNullable(field.getAnnotation(Enumerated.class)).transform(valueEncoding);

            final Pair<Class<Object>, Class<Object>> sourceTargetTypes = TypeParser.determineMapGenericTypes(field);

            final Codec keyCodec = createSimpleCodec(context, sourceTargetTypes.left, maybeEncodingKey);
            final Codec valueCodec = createSimpleCodec(context, sourceTargetTypes.right, maybeEncodingValue);

            return MapCodecBuilder.fromKeyType(keyCodec.sourceType())
                    .toKeyType(keyCodec.targetType())
                    .withKeyCodec(keyCodec)
                    .fromValueType(valueCodec.sourceType())
                    .toValueType(valueCodec.targetType())
                    .withValueCodec(valueCodec);
        }

    }

    Class<?> determineCQL3ValueType(Codec simpleCodec, boolean timeUUID) {
        log.trace("Determine CQL3 type for type {}", simpleCodec.sourceType());
        return determineType(simpleCodec.targetType(), timeUUID);
    }

    Class<?> determineCQL3ValueType(ListCodec listCodec, boolean timeUUID) {
        log.trace("Determine CQL3 type for list type {}", listCodec.sourceType());
        return determineType(listCodec.targetType(), timeUUID);
    }

    Class<?> determineCQL3ValueType(SetCodec setCodec, boolean timeUUID) {
        log.trace("Determine CQL3 type for set type {}", setCodec.sourceType());
        return determineType(setCodec.targetType(), timeUUID);
    }

    Class<?> determineCQL3ValueType(MapCodec mapCodec, boolean timeUUID) {
        log.trace("Determine CQL3 type for map type {}", mapCodec.sourceValueType());
        return determineType(mapCodec.targetValueType(), timeUUID);
    }


    Class<?> determineCQL3KeyType(MapCodec mapCodec, boolean timeUUID) {
        log.trace("Determine CQL3 type for type {}", mapCodec.sourceKeyType());
        return determineType(mapCodec.targetKeyType(), timeUUID);
    }

    private Class<?> determineType(Class<?> input, boolean timeUUID) {
        if (timeUUID && UUID.class.isAssignableFrom(input)) {
            return InternalTimeUUID.class;
        } else if (ByteBuffer.class.isAssignableFrom(input)) {
            return ByteBuffer.class;
        } else if (Counter.class == input) {
            return Long.class;
        } else {
            return input;
        }
    }
    private Codec createSimpleCodec(PropertyParsingContext context, Class type, Optional<Encoding> maybeEncoding) {
        log.debug("Create simple codec for java type {}", type);
        Codec codec;
        if (Byte.class.isAssignableFrom(type) || byte.class.isAssignableFrom(type)) {
            codec = new ByteCodec();
        } else if (byte[].class.isAssignableFrom(type)) {
            codec = new ByteArrayPrimitiveCodec();
        } else if (Byte[].class.isAssignableFrom(type)) {
            codec = new ByteArrayCodec();
        } else if (PropertyParser.isAssignableFromNativeType(type)) {
            codec = new NativeCodec<Object>(type);
        } else if (type.isEnum()) {
            codec = createEnumCodec(type, maybeEncoding);
        } else {
            codec = new JSONCodec<>(context.getCurrentObjectMapper(), type);
        }
        return codec;
    }

    private Codec createEnumCodec(Class type, Optional<Encoding> maybeEncoding) {
        log.debug("Create enum codec for java type {}", type);
        Codec codec;
        final List<Object> enumConstants = Arrays.asList(type.getEnumConstants());
        if (maybeEncoding.isPresent()) {
            if (maybeEncoding.get() == Encoding.NAME) {
                codec = new EnumNameCodec<>(enumConstants, type);
            } else {
                codec = new EnumOrdinalCodec<>(enumConstants, type);
            }
        } else {
            codec = new EnumNameCodec<>(enumConstants, type);
        } return codec;
    }

    private Codec createSimpleCodecForCollection(PropertyParsingContext context) {
        final Field field = context.getCurrentField();
        final Optional<Encoding> maybeEncoding = fromNullable(field.getAnnotation(Enumerated.class)).transform(valueEncoding);
        final Class<Object> valueType = TypeParser.inferValueClassForListOrSet(field.getGenericType(), field.getClass());
        return createSimpleCodec(context, valueType, maybeEncoding);
    }

    public static enum Singleton {
        INSTANCE;

        private final CodecFactory instance = new CodecFactory();

        public CodecFactory get() {
            return instance;
        }
    }
}
TOP

Related Classes of info.archinnov.achilles.internal.metadata.parsing.CodecFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.