From 0c9d255383df4df2c5dd94d7b1d2895eeecb960d Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 20 Feb 2024 11:25:39 +0100 Subject: [PATCH 1/4] Prepare issue branch. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f07ed8723a..f9dc37da05 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-redis - 3.3.0-SNAPSHOT + 3.3.0-GH-2851-SNAPSHOT Spring Data Redis Spring Data module for Redis From f28a23ad58bf4c3f1157295e2ad20589e7775532 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 20 Feb 2024 14:27:25 +0100 Subject: [PATCH 2/4] Use by-id lookup for queries referring to identifier values. Closes #2851 --- .../data/redis/core/RedisQueryEngine.java | 60 ++++++++++++++++-- .../RedisRepositoryIntegrationTestBase.java | 62 +++++++++++++++++++ 2 files changed, 116 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/core/RedisQueryEngine.java b/src/main/java/org/springframework/data/redis/core/RedisQueryEngine.java index 9ae0612e38..c3d8a37f64 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisQueryEngine.java +++ b/src/main/java/org/springframework/data/redis/core/RedisQueryEngine.java @@ -33,18 +33,20 @@ import org.springframework.data.keyvalue.core.SortAccessor; import org.springframework.data.keyvalue.core.SpelSortAccessor; import org.springframework.data.keyvalue.core.query.KeyValueQuery; +import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs; import org.springframework.data.redis.connection.util.ByteArrayWrapper; import org.springframework.data.redis.core.convert.GeoIndexedPropertyValue; +import org.springframework.data.redis.core.convert.RedisConverter; import org.springframework.data.redis.core.convert.RedisData; +import org.springframework.data.redis.core.mapping.RedisPersistentProperty; import org.springframework.data.redis.repository.query.RedisOperationChain; import org.springframework.data.redis.repository.query.RedisOperationChain.NearPath; import org.springframework.data.redis.repository.query.RedisOperationChain.PathAndValue; import org.springframework.data.redis.util.ByteUtils; import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.lang.NonNullApi; import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; @@ -100,7 +102,7 @@ private List doFind(RedisOperationChain criteria, long offset, int rows, RedisCallback>> callback = connection -> { - List keys = findKeys(criteria, rows, keyspace, connection); + List keys = findKeys(criteria, rows, keyspace, type, connection); byte[] keyspaceBin = getRequiredAdapter().getConverter().getConversionService().convert(keyspace + ":", byte[].class); @@ -143,18 +145,35 @@ private List doFind(RedisOperationChain criteria, long offset, int rows, return result; } - private List findKeys(RedisOperationChain criteria, int rows, String keyspace, RedisConnection connection) { + private List findKeys(RedisOperationChain criteria, int rows, String keyspace, Class domainType, + RedisConnection connection) { List allKeys = new ArrayList<>(); if (!criteria.getSismember().isEmpty()) { - allKeys.addAll(connection.sInter(keys(keyspace + ":", criteria.getSismember()))); + + Set sismember = criteria.getSismember(); + if (sismember.size() == 1) { + KeySelector keySelector = KeySelector.of(getRequiredAdapter().getConverter(), sismember, domainType); + if (!keySelector.setValueLookup().isEmpty()) { + allKeys.addAll(connection.sInter(keys(keyspace + ":", keySelector.setValueLookup()))); + } + + allKeys.addAll(keySelector.keys()); + } else { + allKeys.addAll(connection.sInter(keys(keyspace + ":", sismember))); + } } - if (!criteria.getOrSismember().isEmpty()) { + KeySelector keySelector = KeySelector.of(getRequiredAdapter().getConverter(), criteria.getOrSismember(), + domainType); + + if (!keySelector.setValueLookup().isEmpty()) { allKeys.addAll(connection.sUnion(keys(keyspace + ":", criteria.getOrSismember()))); } + allKeys.addAll(keySelector.keys()); + if (criteria.getNear() != null) { GeoRadiusCommandArgs limit = GeoRadiusCommandArgs.newGeoRadiusArgs(); @@ -170,7 +189,6 @@ private List findKeys(RedisOperationChain criteria, int rows, String key } } - Set unique = new LinkedHashSet<>(allKeys.size()); allKeys.forEach(key -> unique.add(new ByteArrayWrapper(key))); @@ -244,4 +262,34 @@ public RedisOperationChain resolve(KeyValueQuery query) { return (RedisOperationChain) query.getCriteria(); } } + + /** + * Value object capturing the direct object keys and set of values that need to be looked up from the secondary + * indexes. + * + * @param keys + * @param setValueLookup + */ + record KeySelector(Collection keys, Set setValueLookup) { + + static KeySelector of(RedisConverter converter, Set pathAndValues, Class domainType) { + + Set keys = new LinkedHashSet<>(); + Set remainder = new LinkedHashSet<>(); + + for (PathAndValue pathAndValue : pathAndValues) { + + PersistentPropertyPath path = converter.getMappingContext() + .getPersistentPropertyPath(pathAndValue.getPath(), domainType); + if (path.getLeafProperty().isIdProperty()) { + byte[] key = converter.getConversionService().convert(pathAndValue.getFirstValue(), byte[].class); + keys.add(key); + } else { + remainder.add(pathAndValue); + } + } + + return new KeySelector(keys, remainder); + } + } } diff --git a/src/test/java/org/springframework/data/redis/repository/RedisRepositoryIntegrationTestBase.java b/src/test/java/org/springframework/data/redis/repository/RedisRepositoryIntegrationTestBase.java index 31e5fc26ad..16d796c114 100644 --- a/src/test/java/org/springframework/data/redis/repository/RedisRepositoryIntegrationTestBase.java +++ b/src/test/java/org/springframework/data/redis/repository/RedisRepositoryIntegrationTestBase.java @@ -27,6 +27,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Reference; @@ -101,6 +102,57 @@ void simpleFindShouldReturnEntitiesCorrectly() { assertThat(repo.findByLastname("al'thor")).contains(rand); } + @Test // GH-2851 + void shouldReturnSingleEntityByIdViaQueryMethod() { + + Person rand = new Person(); + rand.firstname = "rand"; + rand.lastname = "al'thor"; + + Person egwene = new Person(); + egwene.firstname = "egwene"; + + repo.saveAll(Arrays.asList(rand, egwene)); + + assertThat(repo.findEntityById(rand.getId())).isEqualTo(rand); + assertThat(repo.findEntityById(egwene.getId())).isEqualTo(egwene); + } + + @Test // GH-2851 + void shouldProjectSingleResult() { + + Person rand = new Person(); + rand.firstname = "rand"; + rand.lastname = "al'thor"; + + Person egwene = new Person(); + egwene.firstname = "egwene"; + + repo.saveAll(Arrays.asList(rand, egwene)); + + PersonProjection projectionById = repo.findProjectionById(rand.getId()); + assertThat(projectionById).isNotNull(); + assertThat(projectionById.getFirstname()).isEqualTo(rand.firstname); + } + + @Test // GH-2851 + void shouldProjectCollection() { + + Person rand = new Person(); + rand.firstname = "rand"; + rand.lastname = "al'thor"; + + Person egwene = new Person(); + egwene.firstname = "egwene"; + + repo.saveAll(Arrays.asList(rand, egwene)); + + List projectionById = repo.findProjectionBy(); + assertThat(projectionById).hasSize(2) // + .extracting(PersonProjection::getFirstname) // + .contains(rand.getFirstname(), egwene.getFirstname()); + } + @Test // DATAREDIS-425 void simpleFindByMultipleProperties() { @@ -570,10 +622,20 @@ public interface PersonRepository extends PagingAndSortingRepository findByHometownLocationNear(Point point, Distance distance, Pageable pageable); + Person findEntityById(String id); + + PersonProjection findProjectionById(String id); + + List findProjectionBy(); + @Override List findAll(Example example); } + public interface PersonProjection { + String getFirstname(); + } + public interface CityRepository extends CrudRepository { List findByLocationNear(Point point, Distance distance); From 496992771699c1313229c6e76852b39d44c75520 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 21 Feb 2024 09:14:15 +0100 Subject: [PATCH 3/4] Add support for DTO projections. --- .../ROOT/pages/repositories/projections.adoc | 2 +- .../core/convert/MappingRedisConverter.java | 16 +- .../redis/core/convert/RedisConverter.java | 7 + .../EnableRedisRepositories.java | 3 +- .../repository/query/RedisPartTreeQuery.java | 151 ++++++++++++++++++ .../support/RedisRepositoryFactory.java | 4 +- .../support/RedisRepositoryFactoryBean.java | 2 + .../RedisRepositoryIntegrationTestBase.java | 34 +++- 8 files changed, 208 insertions(+), 11 deletions(-) create mode 100644 src/main/java/org/springframework/data/redis/repository/query/RedisPartTreeQuery.java diff --git a/src/main/antora/modules/ROOT/pages/repositories/projections.adoc b/src/main/antora/modules/ROOT/pages/repositories/projections.adoc index 875f61abeb..1fae30fda5 100644 --- a/src/main/antora/modules/ROOT/pages/repositories/projections.adoc +++ b/src/main/antora/modules/ROOT/pages/repositories/projections.adoc @@ -1,4 +1,4 @@ -[[cassandra.projections]] +[[redis.projections]] = Projections include::{commons}@data-commons::page$repositories/projections.adoc[leveloffset=+1] diff --git a/src/main/java/org/springframework/data/redis/core/convert/MappingRedisConverter.java b/src/main/java/org/springframework/data/redis/core/convert/MappingRedisConverter.java index d738a1e95d..e9e1a9f312 100644 --- a/src/main/java/org/springframework/data/redis/core/convert/MappingRedisConverter.java +++ b/src/main/java/org/springframework/data/redis/core/convert/MappingRedisConverter.java @@ -16,8 +16,17 @@ package org.springframework.data.redis.core.convert; import java.lang.reflect.Array; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -1046,6 +1055,11 @@ public IndexResolver getIndexResolver() { return this.indexResolver; } + @Override + public EntityInstantiators getEntityInstantiators() { + return entityInstantiators; + } + @Override public ConversionService getConversionService() { return this.conversionService; diff --git a/src/main/java/org/springframework/data/redis/core/convert/RedisConverter.java b/src/main/java/org/springframework/data/redis/core/convert/RedisConverter.java index e52d942bc4..998f223233 100644 --- a/src/main/java/org/springframework/data/redis/core/convert/RedisConverter.java +++ b/src/main/java/org/springframework/data/redis/core/convert/RedisConverter.java @@ -16,6 +16,7 @@ package org.springframework.data.redis.core.convert; import org.springframework.data.convert.EntityConverter; +import org.springframework.data.mapping.model.EntityInstantiators; import org.springframework.data.redis.core.mapping.RedisMappingContext; import org.springframework.data.redis.core.mapping.RedisPersistentEntity; import org.springframework.data.redis.core.mapping.RedisPersistentProperty; @@ -40,4 +41,10 @@ public interface RedisConverter */ @Nullable IndexResolver getIndexResolver(); + + /** + * @return the configured {@link EntityInstantiators}. + * @since 3.2.4 + */ + EntityInstantiators getEntityInstantiators(); } diff --git a/src/main/java/org/springframework/data/redis/repository/configuration/EnableRedisRepositories.java b/src/main/java/org/springframework/data/redis/repository/configuration/EnableRedisRepositories.java index d236922042..eea89db92b 100644 --- a/src/main/java/org/springframework/data/redis/repository/configuration/EnableRedisRepositories.java +++ b/src/main/java/org/springframework/data/redis/repository/configuration/EnableRedisRepositories.java @@ -33,6 +33,7 @@ import org.springframework.data.redis.core.convert.KeyspaceConfiguration; import org.springframework.data.redis.core.index.IndexConfiguration; import org.springframework.data.redis.listener.KeyExpirationEventMessageListener; +import org.springframework.data.redis.repository.query.RedisPartTreeQuery; import org.springframework.data.redis.repository.query.RedisQueryCreator; import org.springframework.data.redis.repository.support.RedisRepositoryFactoryBean; import org.springframework.data.repository.config.DefaultRepositoryBaseClass; @@ -52,7 +53,7 @@ @Documented @Inherited @Import(RedisRepositoriesRegistrar.class) -@QueryCreatorType(RedisQueryCreator.class) +@QueryCreatorType(value = RedisQueryCreator.class, repositoryQueryType = RedisPartTreeQuery.class) public @interface EnableRedisRepositories { /** diff --git a/src/main/java/org/springframework/data/redis/repository/query/RedisPartTreeQuery.java b/src/main/java/org/springframework/data/redis/repository/query/RedisPartTreeQuery.java new file mode 100644 index 0000000000..8ba04ac02e --- /dev/null +++ b/src/main/java/org/springframework/data/redis/repository/query/RedisPartTreeQuery.java @@ -0,0 +1,151 @@ +/* + * Copyright 2024 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.redis.repository.query; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.convert.DtoInstantiatingConverter; +import org.springframework.data.keyvalue.core.KeyValueOperations; +import org.springframework.data.keyvalue.core.query.KeyValueQuery; +import org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery; +import org.springframework.data.mapping.PersistentEntity; +import org.springframework.data.mapping.PersistentProperty; +import org.springframework.data.mapping.context.MappingContext; +import org.springframework.data.mapping.model.EntityInstantiators; +import org.springframework.data.redis.core.RedisKeyValueAdapter; +import org.springframework.data.redis.core.convert.RedisConverter; +import org.springframework.data.repository.query.ParameterAccessor; +import org.springframework.data.repository.query.ParametersParameterAccessor; +import org.springframework.data.repository.query.QueryMethod; +import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; +import org.springframework.data.repository.query.ResultProcessor; +import org.springframework.data.repository.query.ReturnedType; +import org.springframework.data.repository.query.parser.AbstractQueryCreator; +import org.springframework.data.util.ReflectionUtils; +import org.springframework.data.util.Streamable; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +/** + * Redis-specific implementation of {@link KeyValuePartTreeQuery} supporting projections. + * + * @author Mark Paluch + * @since 3.2.4 + */ +public class RedisPartTreeQuery extends KeyValuePartTreeQuery { + + private final RedisKeyValueAdapter adapter; + + public RedisPartTreeQuery(QueryMethod queryMethod, QueryMethodEvaluationContextProvider evaluationContextProvider, + KeyValueOperations template, Class> queryCreator) { + super(queryMethod, evaluationContextProvider, template, queryCreator); + this.adapter = (RedisKeyValueAdapter) template.getKeyValueAdapter(); + } + + @Override + public Object execute(Object[] parameters) { + + ParameterAccessor accessor = new ParametersParameterAccessor(getQueryMethod().getParameters(), parameters); + KeyValueQuery query = prepareQuery(parameters); + ResultProcessor processor = getQueryMethod().getResultProcessor().withDynamicProjection(accessor); + + RedisConverter converter = adapter.getConverter(); + Converter resultPostProcessor = new ResultProcessingConverter(processor, + converter.getMappingContext(), converter.getEntityInstantiators()); + + Object source = doExecute(parameters, query); + return source != null ? processor.processResult(resultPostProcessor.convert(source)) : null; + } + + /** + * A {@link Converter} to post-process all source objects using the given {@link ResultProcessor}. + * + * @author Mark Paluch + */ + static final class ResultProcessingConverter implements Converter { + + private final ResultProcessor processor; + private final MappingContext, ? extends PersistentProperty> context; + private final EntityInstantiators instantiators; + + public ResultProcessingConverter(ResultProcessor processor, + MappingContext, ? extends PersistentProperty> context, + EntityInstantiators instantiators) { + + Assert.notNull(processor, "Processor must not be null!"); + Assert.notNull(context, "MappingContext must not be null!"); + Assert.notNull(instantiators, "Instantiators must not be null!"); + + this.processor = processor; + this.context = context; + this.instantiators = instantiators; + } + + /* + * (non-Javadoc) + * @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object) + */ + @Override + public Object convert(Object source) { + + if (source instanceof Set s) { + + Set target = new LinkedHashSet<>(s.size()); + + for (Object o : s) { + target.add(convert(o)); + } + + return target; + } + + if (source instanceof Collection c) { + + List target = new ArrayList<>(c.size()); + + for (Object o : c) { + target.add(convert(o)); + } + + return target; + } + + if (source instanceof Streamable s) { + return s.map(this::convert); + } + + ReturnedType returnedType = processor.getReturnedType(); + + if (ReflectionUtils.isVoid(returnedType.getReturnedType())) { + return null; + } + + if (ClassUtils.isPrimitiveOrWrapper(returnedType.getReturnedType())) { + return source; + } + + Converter converter = new DtoInstantiatingConverter(returnedType.getReturnedType(), context, + instantiators); + + return processor.processResult(source, converter); + } + } +} diff --git a/src/main/java/org/springframework/data/redis/repository/support/RedisRepositoryFactory.java b/src/main/java/org/springframework/data/redis/repository/support/RedisRepositoryFactory.java index f960411258..5197d7665c 100644 --- a/src/main/java/org/springframework/data/redis/repository/support/RedisRepositoryFactory.java +++ b/src/main/java/org/springframework/data/redis/repository/support/RedisRepositoryFactory.java @@ -16,11 +16,11 @@ package org.springframework.data.redis.repository.support; import org.springframework.data.keyvalue.core.KeyValueOperations; -import org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery; import org.springframework.data.keyvalue.repository.support.KeyValueRepositoryFactory; import org.springframework.data.redis.core.mapping.RedisMappingContext; import org.springframework.data.redis.core.mapping.RedisPersistentEntity; import org.springframework.data.redis.repository.core.MappingRedisEntityInformation; +import org.springframework.data.redis.repository.query.RedisPartTreeQuery; import org.springframework.data.redis.repository.query.RedisQueryCreator; import org.springframework.data.repository.core.EntityInformation; import org.springframework.data.repository.core.RepositoryMetadata; @@ -59,7 +59,7 @@ public RedisRepositoryFactory(KeyValueOperations keyValueOperations) { */ public RedisRepositoryFactory(KeyValueOperations keyValueOperations, Class> queryCreator) { - this(keyValueOperations, queryCreator, KeyValuePartTreeQuery.class); + this(keyValueOperations, queryCreator, RedisPartTreeQuery.class); } /** diff --git a/src/main/java/org/springframework/data/redis/repository/support/RedisRepositoryFactoryBean.java b/src/main/java/org/springframework/data/redis/repository/support/RedisRepositoryFactoryBean.java index 448364c417..b0ecb53970 100644 --- a/src/main/java/org/springframework/data/redis/repository/support/RedisRepositoryFactoryBean.java +++ b/src/main/java/org/springframework/data/redis/repository/support/RedisRepositoryFactoryBean.java @@ -18,6 +18,7 @@ import org.springframework.beans.factory.FactoryBean; import org.springframework.data.keyvalue.core.KeyValueOperations; import org.springframework.data.keyvalue.repository.support.KeyValueRepositoryFactoryBean; +import org.springframework.data.redis.repository.query.RedisPartTreeQuery; import org.springframework.data.repository.Repository; import org.springframework.data.repository.query.RepositoryQuery; import org.springframework.data.repository.query.parser.AbstractQueryCreator; @@ -44,6 +45,7 @@ public class RedisRepositoryFactoryBean, S, ID> */ public RedisRepositoryFactoryBean(Class repositoryInterface) { super(repositoryInterface); + setQueryType(RedisPartTreeQuery.class); } @Override diff --git a/src/test/java/org/springframework/data/redis/repository/RedisRepositoryIntegrationTestBase.java b/src/test/java/org/springframework/data/redis/repository/RedisRepositoryIntegrationTestBase.java index 16d796c114..94009df445 100644 --- a/src/test/java/org/springframework/data/redis/repository/RedisRepositoryIntegrationTestBase.java +++ b/src/test/java/org/springframework/data/redis/repository/RedisRepositoryIntegrationTestBase.java @@ -51,6 +51,7 @@ import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.query.QueryByExampleExecutor; +import org.springframework.data.util.Streamable; import org.springframework.lang.Nullable; /** @@ -130,9 +131,13 @@ void shouldProjectSingleResult() { repo.saveAll(Arrays.asList(rand, egwene)); - PersonProjection projectionById = repo.findProjectionById(rand.getId()); - assertThat(projectionById).isNotNull(); - assertThat(projectionById.getFirstname()).isEqualTo(rand.firstname); + PersonProjection projection = repo.findProjectionById(rand.getId(), PersonProjection.class); + assertThat(projection).isNotNull(); + assertThat(projection.getFirstname()).isEqualTo(rand.firstname); + + PersonDto dto = repo.findProjectionById(rand.getId(), PersonDto.class); + assertThat(dto).isNotNull(); + assertThat(dto.firstname()).isEqualTo(rand.firstname); } @Test // GH-2851 @@ -147,10 +152,20 @@ void shouldProjectCollection() { repo.saveAll(Arrays.asList(rand, egwene)); - List projectionById = repo.findProjectionBy(); - assertThat(projectionById).hasSize(2) // + List projection = repo.findProjectionBy(); + assertThat(projection).hasSize(2) // .extracting(PersonProjection::getFirstname) // .contains(rand.getFirstname(), egwene.getFirstname()); + + projection = repo.findProjectionStreamBy().toList(); + assertThat(projection).hasSize(2) // + .extracting(PersonProjection::getFirstname) // + .contains(rand.getFirstname(), egwene.getFirstname()); + + List dtos = repo.findProjectionDtoBy(); + assertThat(dtos).hasSize(2) // + .extracting(PersonDto::firstname) // + .contains(rand.getFirstname(), egwene.getFirstname()); } @Test // DATAREDIS-425 @@ -624,10 +639,14 @@ public interface PersonRepository extends PagingAndSortingRepository T findProjectionById(String id, Class projection); + + Streamable findProjectionStreamBy(); List findProjectionBy(); + List findProjectionDtoBy(); + @Override List findAll(Example example); } @@ -636,6 +655,9 @@ public interface PersonProjection { String getFirstname(); } + record PersonDto(String firstname) { + } + public interface CityRepository extends CrudRepository { List findByLocationNear(Point point, Distance distance); From 56144052f410c644fa4b576bd4c40b6ce21e0d33 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 21 Feb 2024 10:47:38 +0100 Subject: [PATCH 4/4] Add reflection hints. --- .../data/redis/aot/RedisRuntimeHints.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/aot/RedisRuntimeHints.java b/src/main/java/org/springframework/data/redis/aot/RedisRuntimeHints.java index 963184e293..d5b1224105 100644 --- a/src/main/java/org/springframework/data/redis/aot/RedisRuntimeHints.java +++ b/src/main/java/org/springframework/data/redis/aot/RedisRuntimeHints.java @@ -46,6 +46,7 @@ import org.springframework.data.redis.core.index.IndexConfiguration; import org.springframework.data.redis.core.mapping.RedisMappingContext; import org.springframework.data.redis.listener.RedisMessageListenerContainer; +import org.springframework.data.redis.repository.query.RedisPartTreeQuery; import org.springframework.data.redis.repository.query.RedisQueryCreator; import org.springframework.data.redis.repository.support.RedisRepositoryFactoryBean; import org.springframework.lang.Nullable; @@ -106,15 +107,15 @@ public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) TypeReference.of(ReactiveClusterScriptingCommands.class), TypeReference.of(ReactiveClusterGeoCommands.class), TypeReference.of(ReactiveClusterHyperLogLogCommands.class), TypeReference.of(ReactiveRedisOperations.class), - TypeReference.of(ReactiveRedisConnectionFactory.class), - TypeReference.of(ReactiveRedisTemplate.class), TypeReference.of(RedisOperations.class), - TypeReference.of(RedisTemplate.class), TypeReference.of(StringRedisTemplate.class), - TypeReference.of(KeyspaceConfiguration.class), TypeReference.of(MappingConfiguration.class), - TypeReference.of(MappingRedisConverter.class), TypeReference.of(RedisConverter.class), - TypeReference.of(RedisCustomConversions.class), TypeReference.of(ReferenceResolver.class), - TypeReference.of(ReferenceResolverImpl.class), TypeReference.of(IndexConfiguration.class), - TypeReference.of(ConfigurableIndexDefinitionProvider.class), TypeReference.of(RedisMappingContext.class), - TypeReference.of(RedisRepositoryFactoryBean.class), TypeReference.of(RedisQueryCreator.class), + TypeReference.of(ReactiveRedisConnectionFactory.class), TypeReference.of(ReactiveRedisTemplate.class), + TypeReference.of(RedisOperations.class), TypeReference.of(RedisTemplate.class), + TypeReference.of(StringRedisTemplate.class), TypeReference.of(KeyspaceConfiguration.class), + TypeReference.of(MappingConfiguration.class), TypeReference.of(MappingRedisConverter.class), + TypeReference.of(RedisConverter.class), TypeReference.of(RedisCustomConversions.class), + TypeReference.of(ReferenceResolver.class), TypeReference.of(ReferenceResolverImpl.class), + TypeReference.of(IndexConfiguration.class), TypeReference.of(ConfigurableIndexDefinitionProvider.class), + TypeReference.of(RedisMappingContext.class), TypeReference.of(RedisRepositoryFactoryBean.class), + TypeReference.of(RedisQueryCreator.class), TypeReference.of(RedisPartTreeQuery.class), TypeReference.of(MessageListener.class), TypeReference.of(RedisMessageListenerContainer.class), TypeReference