From c3c5e7e331d917050f3d7f85f08c7daa65242177 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Sun, 2 Jul 2017 21:37:02 +0200 Subject: [PATCH] DATACMNS-1102 - Avoid superfluous recreation of ConversionService for projections. For repository query methods with a dynamic projection parameter, the ResultProcessor is recreated with the type handed to the method. This results in recreation of the ProjectingConverter, which previously recreated a DefaultConversionService instance (for fallback conversions), which is rather expensive due to the reflection lookups checking for the presence of libraries on the classpath. This is now avoided by using copying methods that reuse the initially created DefaultConversionService. --- .../repository/query/ResultProcessor.java | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/springframework/data/repository/query/ResultProcessor.java b/src/main/java/org/springframework/data/repository/query/ResultProcessor.java index 200d7ed26..e21670f34 100644 --- a/src/main/java/org/springframework/data/repository/query/ResultProcessor.java +++ b/src/main/java/org/springframework/data/repository/query/ResultProcessor.java @@ -15,6 +15,8 @@ */ package org.springframework.data.repository.query; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.NonNull; import lombok.RequiredArgsConstructor; @@ -44,6 +46,7 @@ import org.springframework.util.Assert; * @author Christoph Strobl * @since 1.12 */ +@AllArgsConstructor(access = AccessLevel.PRIVATE) public class ResultProcessor { private final QueryMethod method; @@ -90,9 +93,7 @@ public class ResultProcessor { Assert.notNull(accessor, "Parameter accessor must not be null!"); - return accessor.getDynamicProjection()// - .map(it -> new ResultProcessor(method, factory, it))// - .orElse(this); + return accessor.getDynamicProjection().map(this::withType).orElse(this); } /** @@ -160,6 +161,12 @@ public class ResultProcessor { return (T) converter.convert(source); } + private ResultProcessor withType(Class type) { + + ReturnedType returnedType = ReturnedType.of(type, method.getDomainClass(), factory); + return new ResultProcessor(method, converter.withType(returnedType), factory, returnedType); + } + /** * Creates a new {@link Collection} for the given source. Will try to create an instance of the source collection's * type first falling back to creating an approximate collection if the former fails. @@ -235,7 +242,30 @@ public class ResultProcessor { private final @NonNull ReturnedType type; private final @NonNull ProjectionFactory factory; - private final ConversionService conversionService = new DefaultConversionService(); + private final @NonNull ConversionService conversionService; + + /** + * Creates a new {@link ProjectingConverter} for the given {@link ReturnedType} and {@link ProjectionFactory}. + * + * @param type must not be {@literal null}. + * @param factory must not be {@literal null}. + */ + ProjectingConverter(ReturnedType type, ProjectionFactory factory) { + this(type, factory, new DefaultConversionService()); + } + + /** + * Creates a new {@link ProjectingConverter} for the given {@link ReturnedType}. + * + * @param type must not be {@literal null}. + * @return + */ + ProjectingConverter withType(ReturnedType type) { + + Assert.notNull(type, "ReturnedType must not be null!"); + + return new ProjectingConverter(type, factory, conversionService); + } /* * (non-Javadoc)