From d429d4852cda07a1edd1952a764f54b48a167647 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 | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 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 3cdbb2b4e..46a711891 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; @@ -43,6 +45,7 @@ import org.springframework.util.Assert; * @author John Blum * @since 1.12 */ +@AllArgsConstructor(access = AccessLevel.PRIVATE) public class ResultProcessor { private final QueryMethod method; @@ -94,7 +97,7 @@ public class ResultProcessor { Class projectionType = accessor.getDynamicProjection(); - return projectionType == null ? this : new ResultProcessor(method, factory, projectionType); + return projectionType == null ? this : withType(projectionType); } /** @@ -159,6 +162,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. @@ -238,7 +247,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)