From 68bfa9af0e91c09af1c49ce3e2836447775e8a06 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 11 Feb 2022 15:21:25 +0100 Subject: [PATCH] Performance improvements in `ReactiveWrappers` and `ConvertingPropertyAccessor`. We now cache whether types are reactive wrappers and bypass the ConversionService for assignable primitive values. Closes #2546 --- .../mapping/model/ConvertingPropertyAccessor.java | 5 +++-- .../data/repository/util/ReactiveWrappers.java | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/springframework/data/mapping/model/ConvertingPropertyAccessor.java b/src/main/java/org/springframework/data/mapping/model/ConvertingPropertyAccessor.java index 99f3d732b..bb5944af3 100644 --- a/src/main/java/org/springframework/data/mapping/model/ConvertingPropertyAccessor.java +++ b/src/main/java/org/springframework/data/mapping/model/ConvertingPropertyAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2021 the original author or authors. + * Copyright 2014-2022 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. @@ -21,6 +21,7 @@ import org.springframework.data.mapping.PersistentPropertyAccessor; import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; /** * {@link PersistentPropertyAccessor} that potentially converts the value handed to @@ -103,7 +104,7 @@ public class ConvertingPropertyAccessor extends SimplePersistentPropertyPathA return (S) (source == null // ? null // - : type.isAssignableFrom(source.getClass()) // + : ClassUtils.resolvePrimitiveIfNecessary(type).isAssignableFrom(source.getClass()) // ? source // : conversionService.convert(source, type)); } diff --git a/src/main/java/org/springframework/data/repository/util/ReactiveWrappers.java b/src/main/java/org/springframework/data/repository/util/ReactiveWrappers.java index ae69a2bcb..a67cfe5f8 100644 --- a/src/main/java/org/springframework/data/repository/util/ReactiveWrappers.java +++ b/src/main/java/org/springframework/data/repository/util/ReactiveWrappers.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 the original author or authors. + * Copyright 2016-2022 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. @@ -19,6 +19,9 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; import java.util.Optional; import org.springframework.core.ReactiveTypeDescriptor; @@ -26,6 +29,7 @@ import org.springframework.data.util.ProxyUtils; import org.springframework.data.util.ReflectionUtils; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.ConcurrentReferenceHashMap; /** * Utility class to expose details about reactive wrapper types. This class exposes whether a reactive wrapper is @@ -65,6 +69,11 @@ public abstract class ReactiveWrappers { private static final boolean MUTINY_PRESENT = ClassUtils.isPresent("io.smallrye.mutiny.Multi", ReactiveWrappers.class.getClassLoader()); + private static final Map, Boolean> IS_REACTIVE_TYPE = new ConcurrentReferenceHashMap<>(); + + private static final boolean IS_REACTIVE_AVAILABLE = Arrays.stream(ReactiveLibrary.values()) + .anyMatch(ReactiveWrappers::isAvailable); + private ReactiveWrappers() {} /** @@ -84,7 +93,7 @@ public abstract class ReactiveWrappers { * @return {@literal true} if reactive support is available. */ public static boolean isAvailable() { - return Arrays.stream(ReactiveLibrary.values()).anyMatch(ReactiveWrappers::isAvailable); + return IS_REACTIVE_AVAILABLE; } /** @@ -118,7 +127,7 @@ public abstract class ReactiveWrappers { * @return {@literal true} if the {@code type} is a supported reactive wrapper type. */ public static boolean supports(Class type) { - return isAvailable() && isWrapper(ProxyUtils.getUserClass(type)); + return isAvailable() && IS_REACTIVE_TYPE.computeIfAbsent(type, key -> isWrapper(ProxyUtils.getUserClass(key))); } /**