Package org.terasology.reflection.copy

Source Code of org.terasology.reflection.copy.CopyStrategyLibrary$ReturnAsIsStrategy

/*
* Copyright 2013 MovingBlocks
*
* 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 org.terasology.reflection.copy;

import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.reflection.metadata.ClassMetadata;
import org.terasology.reflection.metadata.DefaultClassMetadata;
import org.terasology.reflection.MappedContainer;
import org.terasology.reflection.copy.strategy.ListCopyStrategy;
import org.terasology.reflection.copy.strategy.MapCopyStrategy;
import org.terasology.reflection.copy.strategy.MappedContainerCopyStrategy;
import org.terasology.reflection.copy.strategy.SetCopyStrategy;
import org.terasology.reflection.reflect.ReflectFactory;
import org.terasology.engine.SimpleUri;
import org.terasology.utilities.ReflectionUtil;

import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* A library of copy strategies.
* <p/>
* This library is should be initialised by registering strategies for a number of core types.  Then as strategies are requested for unknown types,
* new strategies are generated for those types.
* The library knows how to generate strategies for Lists, Sets, Maps and types marked with the MappedContainer annotation.
* If there is any trouble generating a strategy for a type, or it is unknown and generation is not appropriate for the type, a default strategy of returning the value
* to be copied unaltered is returned.
*
* @author Immortius
*/
public class CopyStrategyLibrary {
    private static final Logger logger = LoggerFactory.getLogger(CopyStrategyLibrary.class);

    private Map<Class<?>, CopyStrategy<?>> strategies = Maps.newHashMap();
    private CopyStrategy<?> defaultStrategy = new ReturnAsIsStrategy();
    private ReflectFactory reflectFactory;

    public CopyStrategyLibrary(ReflectFactory reflectFactory) {
        this.reflectFactory = reflectFactory;
    }

    /**
     * Registers a copy strategy for a base type.
     *
     * @param type     The type
     * @param strategy The strategy for copying the type
     * @param <T>      The type
     */
    public <T> void register(Class<T> type, CopyStrategy<T> strategy) {
        strategies.put(type, strategy);
    }

    public void clear() {
        strategies.clear();
    }

    // TODO: Consider CopyStrategyFactory system for Collections and similar
    public CopyStrategy<?> getStrategy(Type genericType) {
        Class<?> typeClass = ReflectionUtil.getClassOfType(genericType);
        if (typeClass == null) {
            logger.error("Cannot obtain class for type {}, using default strategy", genericType);
            return defaultStrategy;
        }

        if (List.class.isAssignableFrom(typeClass)) {
            // For lists, create the handler for the contained type and wrap in a list type handler
            Type parameter = ReflectionUtil.getTypeParameter(genericType, 0);
            if (parameter != null) {
                CopyStrategy<?> contentStrategy = getStrategy(parameter);
                return new ListCopyStrategy<>(contentStrategy);
            }
            logger.error("List field is not parametrized - using default strategy");
            return new ListCopyStrategy<>(defaultStrategy);

        } else if (Set.class.isAssignableFrom(typeClass)) {
            // For sets:
            Type parameter = ReflectionUtil.getTypeParameter(genericType, 0);
            if (parameter != null) {
                CopyStrategy<?> contentStrategy = getStrategy(parameter);
                return new SetCopyStrategy<>(contentStrategy);
            }
            logger.error("Set field is not parametrized - using default strategy");
            return new SetCopyStrategy<>(defaultStrategy);

        } else if (Map.class.isAssignableFrom(typeClass)) {
            // For Maps, create the handler for the value type
            Type keyParameter = ReflectionUtil.getTypeParameter(genericType, 0);
            CopyStrategy<?> keyStrategy;
            if (keyParameter != null) {
                keyStrategy = getStrategy(keyParameter);
            } else {
                logger.error("Map field is missing key parameter - using default strategy");
                keyStrategy = defaultStrategy;
            }

            Type valueParameter = ReflectionUtil.getTypeParameter(genericType, 1);
            CopyStrategy<?> valueStrategy;
            if (valueParameter != null) {
                valueStrategy = getStrategy(valueParameter);
            } else {
                logger.error("Map field is missing value parameter - using default strategy");
                valueStrategy = defaultStrategy;
            }
            return new MapCopyStrategy<>(keyStrategy, valueStrategy);

        } else if (strategies.containsKey(typeClass)) {
            // For known types, just use the handler
            return strategies.get(typeClass);

        } else if (typeClass.getAnnotation(MappedContainer.class) != null) {
            if (Modifier.isAbstract(typeClass.getModifiers())
                    || typeClass.isLocalClass()
                    || (typeClass.isMemberClass() && !Modifier.isStatic(typeClass.getModifiers()))) {
                logger.error("Type {} is not a valid mapped class", typeClass);
                return defaultStrategy;
            }

            try {
                ClassMetadata<?, ?> classMetadata = new DefaultClassMetadata<>(new SimpleUri(), typeClass, reflectFactory, this);
                return new MappedContainerCopyStrategy<>(classMetadata);
            } catch (NoSuchMethodException e) {
                logger.error("Unable to create copy strategy for field of type {}: no publicly accessible default constructor", typeClass.getSimpleName());
                return defaultStrategy;
            }
        } else {
            logger.debug("Using default copy strategy for {}", typeClass);
            strategies.put(typeClass, defaultStrategy);
            return defaultStrategy;
        }
    }

    /**
     * The default copy strategy - returns the original value.
     *
     * @param <T>
     */
    private static class ReturnAsIsStrategy<T> implements CopyStrategy<T> {

        @Override
        public T copy(T value) {
            return value;
        }
    }
}
TOP

Related Classes of org.terasology.reflection.copy.CopyStrategyLibrary$ReturnAsIsStrategy

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.