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

com.nhl.link.rest.runtime.parser.converter.DefaultJsonValueConverterFactory Maven / Gradle / Ivy

package com.nhl.link.rest.runtime.parser.converter;

import com.nhl.link.rest.meta.Types;
import com.nhl.link.rest.meta.compiler.BeanAnalyzer;
import com.nhl.link.rest.meta.compiler.PropertySetter;
import com.nhl.link.rest.parser.converter.CollectionConverter;
import com.nhl.link.rest.parser.converter.EnumConverter;
import com.nhl.link.rest.parser.converter.JsonValueConverter;
import com.nhl.link.rest.parser.converter.LazyConverter;
import com.nhl.link.rest.parser.converter.PojoConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * @since 1.10
 */
public class DefaultJsonValueConverterFactory implements IJsonValueConverterFactory {
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultJsonValueConverterFactory.class);

    protected Map> convertersByJavaType;

    private JsonValueConverter defaultConverter;

    public DefaultJsonValueConverterFactory(Map, JsonValueConverter> knownConverters,
                                            JsonValueConverter defaultConverter) {

        this.defaultConverter = defaultConverter;

        // creating a concurrent copy of the provided map - we'll be expanding it dynamically.
        this.convertersByJavaType = new ConcurrentHashMap<>(knownConverters);
    }

    @Override
    public JsonValueConverter converter(Type valueType) {
        return getOrCreateConverter(valueType, () -> buildOrDefault(valueType));
    }

    @SuppressWarnings("unchecked")
    @Override
    public  Optional> typedConverter(Class valueType) {
        return Optional.ofNullable((JsonValueConverter) getOrCreateConverter(valueType, () -> buildOrNull(valueType)));
    }

    private JsonValueConverter getOrCreateConverter(Type valueType, Supplier> supplier) {
        JsonValueConverter converter = convertersByJavaType.get(valueType);

        if (converter == null) {
            converter = supplier.get();
            if (converter != null) {
                JsonValueConverter existing = convertersByJavaType.putIfAbsent(valueType, converter);
                if (existing != null) {
                    converter = existing;
                }
            }
        }

        return converter;
    }

    private JsonValueConverter buildOrDefault(Type t) {
        return buildConverter(t).orElse(defaultConverter);
    }

    private JsonValueConverter buildOrNull(Type t) {
        return buildConverter(t).orElse(null);
    }

    private Optional> buildConverter(Type t) {
        return Types.getClassForType(t).flatMap(cls -> buildConverter(cls, Optional.of(t)));
    }

    @SuppressWarnings("unchecked")
    private Optional> buildConverter(Class cls, Optional t) {
        if (cls.isEnum()) {
            return Optional.of(enumConverter(cls));
        }

        if (Collection.class.isAssignableFrom(cls)) {
            Class parameterType;
            if (t.isPresent()) {
                parameterType = Types.getClassForTypeArgument(t.get()).orElse(Object.class);
            } else {
                parameterType = Object.class;
            }

            return Optional.ofNullable(collectionConverter(cls, parameterType));
        }

        return Optional.ofNullable(objectConverter(cls));
    }

    @SuppressWarnings("unchecked")
    private > JsonValueConverter enumConverter(Class enumType) {
        return new EnumConverter<>((Class) enumType);
    }

    @SuppressWarnings("unchecked")
    private , E> JsonValueConverter collectionConverter(Class containerType, Class elementType) {
        Supplier containerSupplier;
        if (List.class.equals(containerType) || Collection.class.equals(containerType)) {
            containerSupplier = () -> (T) new ArrayList<>();
        } else if (Set.class.equals(containerType)) {
            containerSupplier = () -> (T) new HashSet<>();
        } else {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Unsupported collection type: " + containerType.getName());
            }
            return null;
        }
        JsonValueConverter elementConverter = new LazyConverter<>(
                () -> typedConverter(elementType).orElse((JsonValueConverter) defaultConverter));
        return new CollectionConverter<>(containerSupplier, elementConverter);
    }

    private JsonValueConverter objectConverter(Class cls) {
        Map setters = BeanAnalyzer.findSetters(cls)
                .collect(Collectors.toMap(PropertySetter::getName, Function.identity()));

        if (setters.isEmpty()) {
            return null;

        } else {
            Map> propertyConverters = setters.values().stream()
                .collect(Collectors.toMap(PropertySetter::getName, setter -> new LazyConverter<>(() -> buildConverter(setter))));
            return new PojoConverter<>(cls, setters, propertyConverters, defaultConverter);
        }
    }

    private JsonValueConverter buildConverter(PropertySetter setter) {
        return converter(setter.getMethod().getGenericParameterTypes()[0]);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy