org.springframework.data.util.NullableWrapperConverters Maven / Gradle / Ivy
/*
* Copyright 2020-2023 the original author or 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 org.springframework.data.util;
import scala.Function0;
import scala.Option;
import scala.runtime.AbstractFunction0;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterRegistry;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ObjectUtils;
import com.google.common.base.Optional;
/**
* Converters to wrap and unwrap nullable wrapper types potentially being available on the classpath. Currently
* supported:
*
* - {@code java.util.Optional}
* - {@code com.google.common.base.Optional}
* - {@code scala.Option}
* - {@code javaslang.control.Option}
* - {@code io.vavr.control.Option}
*
*
* @author Oliver Gierke
* @author Mark Paluch
* @author Christoph Strobl
* @author Maciek Opała
* @author Jens Schauder
* @since 2.4
*/
public abstract class NullableWrapperConverters {
private static final boolean GUAVA_PRESENT = ClassUtils.isPresent("com.google.common.base.Optional",
NullableWrapperConverters.class.getClassLoader());
private static final boolean SCALA_PRESENT = ClassUtils.isPresent("scala.Option",
NullableWrapperConverters.class.getClassLoader());
private static final boolean VAVR_PRESENT = ClassUtils.isPresent("io.vavr.control.Option",
NullableWrapperConverters.class.getClassLoader());
private static final Set WRAPPER_TYPES = new HashSet();
private static final Set UNWRAPPER_TYPES = new HashSet();
private static final Set> UNWRAPPERS = new HashSet>();
private static final Map, Boolean> supportsCache = new ConcurrentReferenceHashMap<>();
static {
WRAPPER_TYPES.add(NullableWrapperToJdk8OptionalConverter.getWrapperType());
UNWRAPPER_TYPES.add(NullableWrapperToJdk8OptionalConverter.getWrapperType());
UNWRAPPERS.add(Jdk8OptionalUnwrapper.INSTANCE);
if (GUAVA_PRESENT) {
WRAPPER_TYPES.add(NullableWrapperToGuavaOptionalConverter.getWrapperType());
UNWRAPPER_TYPES.add(NullableWrapperToGuavaOptionalConverter.getWrapperType());
UNWRAPPERS.add(GuavaOptionalUnwrapper.INSTANCE);
}
if (SCALA_PRESENT) {
WRAPPER_TYPES.add(NullableWrapperToScalaOptionConverter.getWrapperType());
UNWRAPPER_TYPES.add(NullableWrapperToScalaOptionConverter.getWrapperType());
UNWRAPPERS.add(ScalOptionUnwrapper.INSTANCE);
}
if (VAVR_PRESENT) {
WRAPPER_TYPES.add(NullableWrapperToVavrOptionConverter.getWrapperType());
UNWRAPPERS.add(VavrOptionUnwrapper.INSTANCE);
}
}
private NullableWrapperConverters() {}
/**
* Returns whether the given type is a supported wrapper type.
*
* @param type must not be {@literal null}.
* @return
*/
public static boolean supports(Class> type) {
Assert.notNull(type, "Type must not be null");
return supportsCache.computeIfAbsent(type, key -> {
for (WrapperType candidate : WRAPPER_TYPES) {
if (candidate.getType().isAssignableFrom(key)) {
return true;
}
}
return false;
});
}
/**
* Returns whether the given wrapper type supports unwrapping.
*
* @param type must not be {@literal null}.
* @return
*/
public static boolean supportsUnwrapping(Class> type) {
Assert.notNull(type, "Type must not be null");
for (WrapperType candidate : UNWRAPPER_TYPES) {
if (candidate.getType().isAssignableFrom(type)) {
return true;
}
}
return false;
}
public static boolean isSingleValue(Class> type) {
for (WrapperType candidate : WRAPPER_TYPES) {
if (candidate.getType().isAssignableFrom(type)) {
return candidate.isSingleValue();
}
}
return false;
}
/**
* Registers converters for wrapper types found on the classpath.
*
* @param registry must not be {@literal null}.
*/
public static void registerConvertersIn(ConverterRegistry registry) {
Assert.notNull(registry, "ConversionService must not be null");
registry.addConverter(NullableWrapperToJdk8OptionalConverter.INSTANCE);
if (GUAVA_PRESENT) {
registry.addConverter(NullableWrapperToGuavaOptionalConverter.INSTANCE);
}
if (SCALA_PRESENT) {
registry.addConverter(NullableWrapperToScalaOptionConverter.INSTANCE);
}
if (VAVR_PRESENT) {
registry.addConverter(NullableWrapperToVavrOptionConverter.INSTANCE);
}
}
/**
* Unwraps the given source value in case it's one of the currently supported wrapper types detected at runtime.
*
* @param source can be {@literal null}.
* @return
*/
@Nullable
public static Object unwrap(@Nullable Object source) {
if (source == null || !supports(source.getClass())) {
return source;
}
for (Converter
© 2015 - 2024 Weber Informatics LLC | Privacy Policy