From 12e098d424577a7441ee3919a1b3ae0ab93ab365 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Tue, 14 Oct 2025 17:27:39 +0200 Subject: [PATCH] AOT query creation for IgnoreCase generates invalid code block. Fix AOT jdbc repository integration test setup that generated code for a different repository. Closes: #2155 --- .../data/jdbc/repository/aot/JdbcCodeBlocks.java | 3 ++- .../jdbc/repository/aot/PlaceholderAccessor.java | 6 ++++++ .../AotJdbcRepositoryIntegrationTests.java | 3 ++- .../repository/JdbcRepositoryIntegrationTests.java | 12 ++++++++++++ .../aot/AotFragmentTestConfigurationSupport.java | 3 ++- 5 files changed, 24 insertions(+), 3 deletions(-) diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/aot/JdbcCodeBlocks.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/aot/JdbcCodeBlocks.java index 6e43d3de1..bd319639d 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/aot/JdbcCodeBlocks.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/aot/JdbcCodeBlocks.java @@ -65,6 +65,7 @@ import org.springframework.util.StringUtils; * Common code blocks for JDBC AOT Fragment generation. * * @author Mark Paluch + * @author Christoph Strobl * @since 4.0 */ class JdbcCodeBlocks { @@ -368,7 +369,7 @@ class JdbcCodeBlocks { } if (current.isIgnoreCase()) { - builder.addStatement(".ignoreCase(true)"); + builder.add(".ignoreCase(true)"); } } diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/aot/PlaceholderAccessor.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/aot/PlaceholderAccessor.java index 804584a43..21869a234 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/aot/PlaceholderAccessor.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/aot/PlaceholderAccessor.java @@ -16,6 +16,7 @@ package org.springframework.data.jdbc.repository.aot; import java.sql.JDBCType; +import java.util.Collection; import org.jspecify.annotations.Nullable; @@ -37,6 +38,7 @@ import org.springframework.util.Assert; * Utility to access placeholders in AOT processing. * * @author Mark Paluch + * @author Christoph Strobl * @since 4.0 */ class PlaceholderAccessor { @@ -79,6 +81,10 @@ class PlaceholderAccessor { return cp; } + if(value instanceof Collection c && c.iterator().hasNext()) { + return unwrap(c.iterator().next()); + } + throw new IllegalArgumentException("Cannot unwrap value: '%s' to CapturingJdbcValue".formatted(value)); } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/AotJdbcRepositoryIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/AotJdbcRepositoryIntegrationTests.java index 3578f6014..394f18ce0 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/AotJdbcRepositoryIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/AotJdbcRepositoryIntegrationTests.java @@ -40,6 +40,7 @@ import org.springframework.data.repository.core.support.RepositoryComposition; * Integration test for {@link DummyEntityRepository} using JavaConfig with mounted AOT-generated repository methods. * * @author Mark Paluch + * @author Christoph Strobl */ @IntegrationTest @EnabledOnDatabase(DatabaseType.H2) @@ -59,7 +60,7 @@ class AotJdbcRepositoryIntegrationTests extends JdbcRepositoryIntegrationTests { @Bean static AotFragmentTestConfigurationSupport aot() { - return new AotFragmentTestConfigurationSupport(UserRepository.class, JdbcH2Dialect.INSTANCE, AotConfig.class, + return new AotFragmentTestConfigurationSupport(DummyEntityRepository.class, JdbcH2Dialect.INSTANCE, AotConfig.class, false); } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java index c9c043b9a..b4f8e101d 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java @@ -102,6 +102,7 @@ import org.springframework.test.jdbc.JdbcTestUtils; * @author Christopher Klein * @author Mikhail Polivakha * @author Paul Jones + * @author Christoph Strobl */ @IntegrationTest public class JdbcRepositoryIntegrationTests { @@ -575,6 +576,15 @@ public class JdbcRepositoryIntegrationTests { assertThat(repository.findByNameContains("a", Limit.unlimited())).hasSize(3); } + @Test // GH-2155 + public void selectContainingIgnoreCase() { + + repository.saveAll(Arrays.asList(new DummyEntity("1a1"), new DummyEntity("1B1"), new DummyEntity("1c1"))); + + Optional result = repository.findByNameContainingIgnoreCase("b"); + assertThat(result).map(DummyEntity::getName).contains("1B1"); + } + @Test // GH-774 public void sliceByNameShouldReturnCorrectResult() { @@ -1567,6 +1577,8 @@ public class JdbcRepositoryIntegrationTests { List findByNameContains(String name, Limit limit); + Optional findByNameContainingIgnoreCase(String partialName); + Page findPageProjectionByName(String name, Pageable pageable); Slice findSliceByNameContains(String name, Pageable pageable); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/aot/AotFragmentTestConfigurationSupport.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/aot/AotFragmentTestConfigurationSupport.java index 15f9bd1fd..2af253245 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/aot/AotFragmentTestConfigurationSupport.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/aot/AotFragmentTestConfigurationSupport.java @@ -65,6 +65,7 @@ import org.springframework.util.ReflectionUtils; * invocations to the backing AOT fragment. Note that {@code repositoryInterface} is not a repository proxy. * * @author Mark Paluch + * @author Christoph Strobl */ public class AotFragmentTestConfigurationSupport implements BeanFactoryPostProcessor { @@ -105,7 +106,7 @@ public class AotFragmentTestConfigurationSupport implements BeanFactoryPostProce jdbcRepositoryContributor.contribute(generationContext); AbstractBeanDefinition aotGeneratedRepository = BeanDefinitionBuilder - .genericBeanDefinition(repositoryInterface.getName() + "Impl__AotRepository") + .genericBeanDefinition(repositoryInterface.getPackageName() + "." + repositoryInterface.getSimpleName() + "Impl__AotRepository") .addConstructorArgValue(new RuntimeBeanReference(JdbcAggregateOperations.class)) .addConstructorArgValue(new RuntimeBeanReference(RowMapperFactory.class)) .addConstructorArgValue(