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

io.micronaut.validation.validator.extractors.DefaultValueExtractors Maven / Gradle / Ivy

There is a newer version: 3.10.4
Show newest version
/*
 * Copyright 2017-2020 original authors
 *
 * 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
 *
 * https://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 io.micronaut.validation.validator.extractors;

import io.micronaut.context.BeanContext;
import io.micronaut.context.BeanRegistration;
import io.micronaut.core.annotation.Introspected;
import io.micronaut.core.beans.BeanProperty;
import io.micronaut.core.beans.BeanWrapper;
import io.micronaut.core.type.Argument;
import io.micronaut.core.util.ArrayUtils;
import io.micronaut.core.util.CollectionUtils;

import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.validation.valueextraction.UnwrapByDefault;
import javax.validation.valueextraction.ValueExtractor;
import java.util.*;

/**
 * The default value extractors.
 *
 * @author graemerocher
 * @since 1.2
 */
@Singleton
@Introspected
public class DefaultValueExtractors implements ValueExtractorRegistry {

    public static final String ITERABLE_ELEMENT_NODE_NAME = "";
    public static final String LIST_ELEMENT_NODE_NAME = "";
    public static final String MAP_VALUE_NODE_NAME = "";

    private final UnwrapByDefaultValueExtractor optionalValueExtractor =
            (originalValue, receiver) -> receiver.value(null, originalValue.orElse(null));
    private final UnwrapByDefaultValueExtractor optionalIntValueExtractor =
            (originalValue, receiver) -> receiver.value(null, originalValue.isPresent() ? originalValue.getAsInt() : null);
    private final UnwrapByDefaultValueExtractor optionalLongValueExtractor =
            (originalValue, receiver) -> receiver.value(null, originalValue.isPresent() ? originalValue.getAsLong() : null);
    private final UnwrapByDefaultValueExtractor optionalDoubleValueExtractor =
            (originalValue, receiver) -> receiver.value(null, originalValue.isPresent() ? originalValue.getAsDouble() : null);

    private final ValueExtractor iterableValueExtractor = (originalValue, receiver) -> {
        if (originalValue instanceof List) {
            int i = 0;
            for (Object o : originalValue) {
                receiver.indexedValue(LIST_ELEMENT_NODE_NAME, i++, o);
            }
        } else {
            for (Object o : originalValue) {
                receiver.iterableValue(ITERABLE_ELEMENT_NODE_NAME, o);
            }
        }
    };
    private final ValueExtractor> mapValueExtractor = (originalValue, receiver) -> {
        for (Map.Entry entry : originalValue.entrySet()) {
            receiver.keyedValue(MAP_VALUE_NODE_NAME, entry.getKey(), entry.getValue());
        }
    };
    private final ValueExtractor objectArrayValueExtractor = (originalValue, receiver) -> {
        for (int i = 0; i < originalValue.length; i++) {
            receiver.indexedValue(LIST_ELEMENT_NODE_NAME, i, originalValue[i]);
        }
    };

    private final ValueExtractor intArrayValueExtractor = (originalValue, receiver) -> {
        for (int i = 0; i < originalValue.length; i++) {
            receiver.indexedValue(LIST_ELEMENT_NODE_NAME, i, originalValue[i]);
        }
    };

    private final ValueExtractor byteArrayValueExtractor = (originalValue, receiver) -> {
        for (int i = 0; i < originalValue.length; i++) {
            receiver.indexedValue(LIST_ELEMENT_NODE_NAME, i, originalValue[i]);
        }
    };

    private final ValueExtractor booleanArrayValueExtractor = (originalValue, receiver) -> {
        for (int i = 0; i < originalValue.length; i++) {
            receiver.indexedValue(LIST_ELEMENT_NODE_NAME, i, originalValue[i]);
        }
    };

    private final ValueExtractor doubleArrayValueExtractor = (originalValue, receiver) -> {
        for (int i = 0; i < originalValue.length; i++) {
            receiver.indexedValue(LIST_ELEMENT_NODE_NAME, i, originalValue[i]);
        }
    };

    private final ValueExtractor charArrayValueExtractor = (originalValue, receiver) -> {
        for (int i = 0; i < originalValue.length; i++) {
            receiver.indexedValue(LIST_ELEMENT_NODE_NAME, i, originalValue[i]);
        }
    };

    private final ValueExtractor floatArrayValueExtractor = (originalValue, receiver) -> {
        for (int i = 0; i < originalValue.length; i++) {
            receiver.indexedValue(LIST_ELEMENT_NODE_NAME, i, originalValue[i]);
        }
    };

    private final ValueExtractor shortArrayValueExtractor = (originalValue, receiver) -> {
        for (int i = 0; i < originalValue.length; i++) {
            receiver.indexedValue(LIST_ELEMENT_NODE_NAME, i, originalValue[i]);
        }
    };

    private final Map valueExtractors;
    private final Set unwrapByDefaultTypes = new HashSet<>(5);

    /**
     * Default constructor.
     */
    public DefaultValueExtractors() {
        this(null);
    }

    /**
     * Constructor used during DI.
     *
     * @param beanContext The bean context
     */
    @Inject
    protected DefaultValueExtractors(@Nullable BeanContext beanContext) {
        BeanWrapper wrapper = BeanWrapper.findWrapper(this).orElse(null);
        Map extractorMap = new HashMap<>();

        if (beanContext != null && beanContext.containsBean(ValueExtractor.class)) {
            final Collection> valueExtractors =
                    beanContext.getBeanRegistrations(ValueExtractor.class);
            if (CollectionUtils.isNotEmpty(valueExtractors)) {
                for (BeanRegistration reg : valueExtractors) {
                    final ValueExtractor valueExtractor = reg.getBean();
                    final Class[] typeParameters = reg.getBeanDefinition().getTypeParameters(ValueExtractor.class);
                    if (ArrayUtils.isNotEmpty(typeParameters)) {
                        final Class targetType = typeParameters[0];
                        extractorMap.put(targetType, valueExtractor);
                        if (valueExtractor instanceof UnwrapByDefaultValueExtractor || valueExtractor.getClass().isAnnotationPresent(UnwrapByDefault.class)) {
                            unwrapByDefaultTypes.add(targetType);
                        }
                    }
                }
            }
        }

        if (wrapper != null) {

            final Collection> properties = wrapper.getBeanProperties();
            for (BeanProperty property : properties) {
                if (ValueExtractor.class.isAssignableFrom(property.getType())) {
                    final ValueExtractor valueExtractor = wrapper
                            .getProperty(property.getName(), ValueExtractor.class).orElse(null);
                    final Class targetType = property.asArgument().getFirstTypeVariable().map(Argument::getType).orElse(null);
                    extractorMap.put(targetType, valueExtractor);
                    if (valueExtractor instanceof UnwrapByDefaultValueExtractor || valueExtractor.getClass().isAnnotationPresent(UnwrapByDefault.class)) {
                        unwrapByDefaultTypes.add(targetType);
                    }
                }
            }
            this.valueExtractors = new HashMap<>(extractorMap.size());
            this.valueExtractors.putAll(extractorMap);
        } else {
            this.valueExtractors = Collections.emptyMap();
        }
    }

    /**
     * Value extractor for optional.
     *
     * @return The value extractor.
     */
    public UnwrapByDefaultValueExtractor getOptionalValueExtractor() {
        return optionalValueExtractor;
    }

    /**
     * Value extractor for {@link OptionalInt}.
     *
     * @return The value extractor
     */
    public UnwrapByDefaultValueExtractor getOptionalIntValueExtractor() {
        return optionalIntValueExtractor;
    }

    /**
     * Value extractor for {@link OptionalLong}.
     *
     * @return The value extractor
     */
    public UnwrapByDefaultValueExtractor getOptionalLongValueExtractor() {
        return optionalLongValueExtractor;
    }

    /**
     * Value extractor for {@link OptionalDouble}.
     *
     * @return The value extractor
     */
    public UnwrapByDefaultValueExtractor getOptionalDoubleValueExtractor() {
        return optionalDoubleValueExtractor;
    }

    /**
     * Value extractor for iterable.
     * @return The value extractor
     */
    public ValueExtractor getIterableValueExtractor() {
        return iterableValueExtractor;
    }

    /**
     * Value extractor for iterable.
     * @return The value extractor
     */
    public ValueExtractor> getMapValueExtractor() {
        return mapValueExtractor;
    }

    /**
     * Value extractor for Object[].
     * @return The object[] extractor
     */
    public ValueExtractor getObjectArrayValueExtractor() {
        return objectArrayValueExtractor;
    }

    /**
     * Value extractor for int[].
     * @return The int[] extractor
     */
    public ValueExtractor getIntArrayValueExtractor() {
        return intArrayValueExtractor;
    }

    /**
     * Value extractor for byte[].
     * @return The byte[] extractor
     */
    public ValueExtractor getByteArrayValueExtractor() {
        return byteArrayValueExtractor;
    }

    /**
     * Value extractor for char[].
     * @return The char[] extractor
     */
    public ValueExtractor getCharArrayValueExtractor() {
        return charArrayValueExtractor;
    }

    /**
     * Value extractor for boolean[].
     * @return The boolean[] extractor
     */
    public ValueExtractor getBooleanArrayValueExtractor() {
        return booleanArrayValueExtractor;
    }

    /**
     * Value extractor for double[].
     * @return The double[] extractor
     */
    public ValueExtractor getDoubleArrayValueExtractor() {
        return doubleArrayValueExtractor;
    }

    /**
     * Value extractor for float[].
     * @return The float[] extractor
     */
    public ValueExtractor getFloatArrayValueExtractor() {
        return floatArrayValueExtractor;
    }

    /**
     * Value extractor for short[].
     * @return The short[] extractor
     */
    public ValueExtractor getShortArrayValueExtractor() {
        return shortArrayValueExtractor;
    }

    @SuppressWarnings("unchecked")
    @NonNull
    @Override
    public  Optional> findValueExtractor(@NonNull Class targetType) {
        final ValueExtractor valueExtractor = valueExtractors.get(targetType);
        if (valueExtractor != null) {
            return Optional.of(valueExtractor);
        } else {
            return (Optional) valueExtractors.entrySet().stream()
                    .filter(entry -> entry.getKey().isAssignableFrom(targetType))
                    .map(Map.Entry::getValue)
                    .findFirst();
        }
    }

    @SuppressWarnings("unchecked")
    @NonNull
    @Override
    public  Optional> findUnwrapValueExtractor(@NonNull Class targetType) {
        if (unwrapByDefaultTypes.contains(targetType)) {
            return Optional.ofNullable(valueExtractors.get(targetType));
        }
        return Optional.empty();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy