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.*;
@Singleton
@Introspected
public class implements ValueExtractorRegistry {
public static final String = "<iterable element>";
public static final String = "<list element>";
public static final String = "<map value>";
private final UnwrapByDefaultValueExtractor<Optional> =
(originalValue, receiver) -> receiver.value(null, originalValue.orElse(null));
private final UnwrapByDefaultValueExtractor<OptionalInt> =
(originalValue, receiver) -> receiver.value(null, originalValue.isPresent() ? originalValue.getAsInt() : null);
private final UnwrapByDefaultValueExtractor<OptionalLong> =
(originalValue, receiver) -> receiver.value(null, originalValue.isPresent() ? originalValue.getAsLong() : null);
private final UnwrapByDefaultValueExtractor<OptionalDouble> =
(originalValue, receiver) -> receiver.value(null, originalValue.isPresent() ? originalValue.getAsDouble() : null);
private final ValueExtractor<Iterable> = (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<Map<?, ?>> = (originalValue, receiver) -> {
for (Map.Entry<?, ?> entry : originalValue.entrySet()) {
receiver.keyedValue(MAP_VALUE_NODE_NAME, entry.getKey(), entry.getValue());
}
};
private final ValueExtractor<Object[]> = (originalValue, receiver) -> {
for (int i = 0; i < originalValue.length; i++) {
receiver.indexedValue(LIST_ELEMENT_NODE_NAME, i, originalValue[i]);
}
};
private final ValueExtractor<int[]> = (originalValue, receiver) -> {
for (int i = 0; i < originalValue.length; i++) {
receiver.indexedValue(LIST_ELEMENT_NODE_NAME, i, originalValue[i]);
}
};
private final ValueExtractor<byte[]> = (originalValue, receiver) -> {
for (int i = 0; i < originalValue.length; i++) {
receiver.indexedValue(LIST_ELEMENT_NODE_NAME, i, originalValue[i]);
}
};
private final ValueExtractor<boolean[]> = (originalValue, receiver) -> {
for (int i = 0; i < originalValue.length; i++) {
receiver.indexedValue(LIST_ELEMENT_NODE_NAME, i, originalValue[i]);
}
};
private final ValueExtractor<double[]> = (originalValue, receiver) -> {
for (int i = 0; i < originalValue.length; i++) {
receiver.indexedValue(LIST_ELEMENT_NODE_NAME, i, originalValue[i]);
}
};
private final ValueExtractor<char[]> = (originalValue, receiver) -> {
for (int i = 0; i < originalValue.length; i++) {
receiver.indexedValue(LIST_ELEMENT_NODE_NAME, i, originalValue[i]);
}
};
private final ValueExtractor<float[]> = (originalValue, receiver) -> {
for (int i = 0; i < originalValue.length; i++) {
receiver.indexedValue(LIST_ELEMENT_NODE_NAME, i, originalValue[i]);
}
};
private final ValueExtractor<short[]> = (originalValue, receiver) -> {
for (int i = 0; i < originalValue.length; i++) {
receiver.indexedValue(LIST_ELEMENT_NODE_NAME, i, originalValue[i]);
}
};
private final Map<Class, ValueExtractor> ;
private final Set<Class> = new HashSet<>(5);
public () {
this(null);
}
@Inject
protected (@Nullable BeanContext beanContext) {
BeanWrapper<DefaultValueExtractors> wrapper = BeanWrapper.findWrapper(this).orElse(null);
Map<Class, ValueExtractor> extractorMap = new HashMap<>();
if (beanContext != null && beanContext.containsBean(ValueExtractor.class)) {
final Collection<BeanRegistration<ValueExtractor>> valueExtractors =
beanContext.getBeanRegistrations(ValueExtractor.class);
if (CollectionUtils.isNotEmpty(valueExtractors)) {
for (BeanRegistration<ValueExtractor> 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<BeanProperty<DefaultValueExtractors, Object>> properties = wrapper.getBeanProperties();
for (BeanProperty<DefaultValueExtractors, Object> 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();
}
}
public UnwrapByDefaultValueExtractor<Optional> () {
return optionalValueExtractor;
}
public UnwrapByDefaultValueExtractor<OptionalInt> () {
return optionalIntValueExtractor;
}
public UnwrapByDefaultValueExtractor<OptionalLong> () {
return optionalLongValueExtractor;
}
public UnwrapByDefaultValueExtractor<OptionalDouble> () {
return optionalDoubleValueExtractor;
}
public ValueExtractor<Iterable> () {
return iterableValueExtractor;
}
public ValueExtractor<Map<?, ?>> () {
return mapValueExtractor;
}
public ValueExtractor<Object[]> () {
return objectArrayValueExtractor;
}
public ValueExtractor<int[]> () {
return intArrayValueExtractor;
}
public ValueExtractor<byte[]> () {
return byteArrayValueExtractor;
}
public ValueExtractor<char[]> () {
return charArrayValueExtractor;
}
public ValueExtractor<boolean[]> () {
return booleanArrayValueExtractor;
}
public ValueExtractor<double[]> () {
return doubleArrayValueExtractor;
}
public ValueExtractor<float[]> () {
return floatArrayValueExtractor;
}
public ValueExtractor<short[]> () {
return shortArrayValueExtractor;
}
@SuppressWarnings("unchecked")
@NonNull
@Override
public <T> Optional<ValueExtractor<T>> (@NonNull Class<T> 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 <T> Optional<ValueExtractor<T>> (@NonNull Class<T> targetType) {
if (unwrapByDefaultTypes.contains(targetType)) {
return Optional.ofNullable(valueExtractors.get(targetType));
}
return Optional.empty();
}
}