From fb3745bb13468b36883690fc250d24c4e33c157a Mon Sep 17 00:00:00 2001 From: Auri Munoz Date: Fri, 19 Jul 2024 10:51:09 +0200 Subject: [PATCH] Support Spring Data JpaRepository#getReferenceById and a few delete methods that were lacking Fixes #41987 --- .../generate/StockMethodsAdder.java | 90 ++++++++++++++++--- .../BasicTypeDataRepositoryTest.java | 54 +++++++++++ .../data/runtime/RepositorySupport.java | 30 +++++++ 3 files changed, 161 insertions(+), 13 deletions(-) diff --git a/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/generate/StockMethodsAdder.java b/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/generate/StockMethodsAdder.java index 372e6a05fe75e..38c29bcf432e5 100644 --- a/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/generate/StockMethodsAdder.java +++ b/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/generate/StockMethodsAdder.java @@ -99,6 +99,10 @@ public void add(ClassCreator classCreator, FieldDescriptor entityClassFieldDescr allMethodsToBeImplementedToResult); generateGetOne(classCreator, entityClassFieldDescriptor, generatedClassName, entityTypeStr, idTypeStr, allMethodsToBeImplementedToResult); + generateGetReferenceById(classCreator, entityClassFieldDescriptor, generatedClassName, entityTypeStr, idTypeStr, + allMethodsToBeImplementedToResult); + generateGetById(classCreator, entityClassFieldDescriptor, generatedClassName, entityTypeStr, idTypeStr, + allMethodsToBeImplementedToResult); generateFindAll(classCreator, entityClassFieldDescriptor, generatedClassName, entityTypeStr, allMethodsToBeImplementedToResult); generateFindAllWithSort(classCreator, entityClassFieldDescriptor, generatedClassName, entityTypeStr, @@ -115,6 +119,12 @@ public void add(ClassCreator classCreator, FieldDescriptor entityClassFieldDescr generateDeleteAll(classCreator, entityClassFieldDescriptor, generatedClassName, allMethodsToBeImplementedToResult); generateDeleteAllInBatch(classCreator, entityClassFieldDescriptor, generatedClassName, allMethodsToBeImplementedToResult); + generateDeleteAllInBatchWithIterable(classCreator, generatedClassName, entityTypeStr, + allMethodsToBeImplementedToResult); + generateDeleteInBatchWithIterable(classCreator, generatedClassName, entityTypeStr, + allMethodsToBeImplementedToResult); + generateDeleteAllByIdInBatchWithIterable(classCreator, generatedClassName, entityTypeStr, + allMethodsToBeImplementedToResult); handleUnimplementedMethods(classCreator, allMethodsToBeImplementedToResult); } @@ -508,19 +518,42 @@ private void generateExistsById(ClassCreator classCreator, FieldDescriptor entit private void generateGetOne(ClassCreator classCreator, FieldDescriptor entityClassFieldDescriptor, String generatedClassName, String entityTypeStr, String idTypeStr, Map allMethodsToBeImplementedToResult) { + generateSpecificFindEntityReference(classCreator, entityClassFieldDescriptor, generatedClassName, entityTypeStr, + idTypeStr, "getOne", allMethodsToBeImplementedToResult); + + } + + private void generateGetById(ClassCreator classCreator, FieldDescriptor entityClassFieldDescriptor, + String generatedClassName, String entityTypeStr, String idTypeStr, + Map allMethodsToBeImplementedToResult) { - MethodDescriptor getOneDescriptor = MethodDescriptor.ofMethod(generatedClassName, "getOne", + generateSpecificFindEntityReference(classCreator, entityClassFieldDescriptor, generatedClassName, entityTypeStr, + idTypeStr, "getById", allMethodsToBeImplementedToResult); + } + + private void generateGetReferenceById(ClassCreator classCreator, FieldDescriptor entityClassFieldDescriptor, + String generatedClassName, String entityTypeStr, String idTypeStr, + Map allMethodsToBeImplementedToResult) { + + generateSpecificFindEntityReference(classCreator, entityClassFieldDescriptor, generatedClassName, entityTypeStr, + idTypeStr, "getReferenceById", allMethodsToBeImplementedToResult); + } + + private void generateSpecificFindEntityReference(ClassCreator classCreator, FieldDescriptor entityClassFieldDescriptor, + String generatedClassName, String entityTypeStr, String idTypeStr, String actualMethodName, + Map allMethodsToBeImplementedToResult) { + MethodDescriptor getReferenceByIdDescriptor = MethodDescriptor.ofMethod(generatedClassName, actualMethodName, entityTypeStr, idTypeStr); - MethodDescriptor bridgeGetOneDescriptor = MethodDescriptor.ofMethod(generatedClassName, "getOne", + MethodDescriptor bridgegetReferenceByIdDescriptor = MethodDescriptor.ofMethod(generatedClassName, actualMethodName, Object.class, Object.class); - if (allMethodsToBeImplementedToResult.containsKey(getOneDescriptor) - || allMethodsToBeImplementedToResult.containsKey(bridgeGetOneDescriptor)) { + if (allMethodsToBeImplementedToResult.containsKey(getReferenceByIdDescriptor) + || allMethodsToBeImplementedToResult.containsKey(bridgegetReferenceByIdDescriptor)) { - if (!classCreator.getExistingMethods().contains(getOneDescriptor)) { - try (MethodCreator findById = classCreator.getMethodCreator(getOneDescriptor)) { + if (!classCreator.getExistingMethods().contains(getReferenceByIdDescriptor)) { + try (MethodCreator findById = classCreator.getMethodCreator(getReferenceByIdDescriptor)) { - ResultHandle entity = findById.invokeStaticMethod(ofMethod(RepositorySupport.class, "getOne", + ResultHandle entity = findById.invokeStaticMethod(ofMethod(RepositorySupport.class, actualMethodName, Object.class, AbstractJpaOperations.class, Class.class, Object.class), findById.readStaticField(operationsField), findById.readInstanceField(entityClassFieldDescriptor, findById.getThis()), @@ -528,19 +561,19 @@ private void generateGetOne(ClassCreator classCreator, FieldDescriptor entityCla findById.returnValue(entity); } - try (MethodCreator bridgeGetOne = classCreator.getMethodCreator(bridgeGetOneDescriptor)) { - MethodDescriptor getOne = MethodDescriptor.ofMethod(generatedClassName, "getOne", + try (MethodCreator bridgeGetOne = classCreator.getMethodCreator(bridgegetReferenceByIdDescriptor)) { + MethodDescriptor getReferenceById = MethodDescriptor.ofMethod(generatedClassName, actualMethodName, entityTypeStr, idTypeStr); ResultHandle methodParam = bridgeGetOne.getMethodParam(0); ResultHandle castedMethodParam = bridgeGetOne.checkCast(methodParam, idTypeStr); - ResultHandle result = bridgeGetOne.invokeVirtualMethod(getOne, bridgeGetOne.getThis(), + ResultHandle result = bridgeGetOne.invokeVirtualMethod(getReferenceById, bridgeGetOne.getThis(), castedMethodParam); bridgeGetOne.returnValue(result); } } - allMethodsToBeImplementedToResult.put(getOneDescriptor, true); - allMethodsToBeImplementedToResult.put(bridgeGetOneDescriptor, true); + allMethodsToBeImplementedToResult.put(getReferenceByIdDescriptor, true); + allMethodsToBeImplementedToResult.put(bridgegetReferenceByIdDescriptor, true); } } @@ -886,10 +919,41 @@ private void generateDelete(ClassCreator classCreator, String generatedClassName allMethodsToBeImplementedToResult.put(bridgeDeleteDescriptor, true); } + private void generateDeleteInBatchWithIterable(ClassCreator classCreator, String generatedClassName, String entityTypeStr, + Map allMethodsToBeImplementedToResult) { + generateSpecificDeleteAllWithIterable(classCreator, generatedClassName, entityTypeStr, "deleteInBatch", + allMethodsToBeImplementedToResult); + + } + + private void generateDeleteAllInBatchWithIterable(ClassCreator classCreator, String generatedClassName, + String entityTypeStr, + Map allMethodsToBeImplementedToResult) { + generateSpecificDeleteAllWithIterable(classCreator, generatedClassName, entityTypeStr, "deleteAllInBatch", + allMethodsToBeImplementedToResult); + + } + + private void generateDeleteAllByIdInBatchWithIterable(ClassCreator classCreator, String generatedClassName, + String entityTypeStr, + Map allMethodsToBeImplementedToResult) { + generateSpecificDeleteAllWithIterable(classCreator, generatedClassName, entityTypeStr, "deleteAllByIdInBatch", + allMethodsToBeImplementedToResult); + + } + private void generateDeleteAllWithIterable(ClassCreator classCreator, String generatedClassName, String entityTypeStr, Map allMethodsToBeImplementedToResult) { + generateSpecificDeleteAllWithIterable(classCreator, generatedClassName, entityTypeStr, "deleteAll", + allMethodsToBeImplementedToResult); + + } + + private void generateSpecificDeleteAllWithIterable(ClassCreator classCreator, String generatedClassName, + String entityTypeStr, String actualMethodName, + Map allMethodsToBeImplementedToResult) { - MethodDescriptor deleteAllWithIterableDescriptor = MethodDescriptor.ofMethod(generatedClassName, "deleteAll", + MethodDescriptor deleteAllWithIterableDescriptor = MethodDescriptor.ofMethod(generatedClassName, actualMethodName, void.class, Iterable.class); if (allMethodsToBeImplementedToResult.containsKey(deleteAllWithIterableDescriptor)) { diff --git a/extensions/spring-data-jpa/deployment/src/test/java/io/quarkus/spring/data/deployment/BasicTypeDataRepositoryTest.java b/extensions/spring-data-jpa/deployment/src/test/java/io/quarkus/spring/data/deployment/BasicTypeDataRepositoryTest.java index 52f3b65dd8084..1682b40fb2b6c 100644 --- a/extensions/spring-data-jpa/deployment/src/test/java/io/quarkus/spring/data/deployment/BasicTypeDataRepositoryTest.java +++ b/extensions/spring-data-jpa/deployment/src/test/java/io/quarkus/spring/data/deployment/BasicTypeDataRepositoryTest.java @@ -7,6 +7,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.time.Duration; +import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Set; @@ -21,6 +22,7 @@ import org.hibernate.Hibernate; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; @@ -148,6 +150,58 @@ public void testListOrderByNullHandling() throws MalformedURLException { assertEquals(uuidForTheNullUrlRecord, list.get(list.size() - 1).getUuid()); } + @Test + @Order(9) + @Transactional + public void testGetReferenceById() throws Exception { + populateData(new BasicTypeData()); + assertThat(repo.getReferenceById(1)).isNotNull(); + } + + @Test + @Order(10) + @Transactional + public void testGetOne() throws Exception { + populateData(new BasicTypeData()); + assertThat(repo.getOne(1)).isNotNull(); + } + + @Test + @Order(11) + @Transactional + public void testGetById() throws Exception { + populateData(new BasicTypeData()); + assertThat(repo.getReferenceById(1)).isNotNull(); + } + + @Test + @Order(12) + @Transactional + public void testDeleteAllInBatch() throws Exception { + Assertions.assertDoesNotThrow(() -> repo.deleteAllInBatch()); + } + + @Test + @Order(13) + @Transactional + public void testDeleteAllInBatchWithIterable() throws Exception { + Assertions.assertDoesNotThrow(() -> repo.deleteAllInBatch(new ArrayList<>())); + } + + @Test + @Order(14) + @Transactional + public void testDeleteInBatch() throws Exception { + Assertions.assertDoesNotThrow(() -> repo.deleteInBatch(new ArrayList<>())); + } + + @Test + @Order(15) + @Transactional + public void testDeleteAllByIdInBatch() throws Exception { + Assertions.assertDoesNotThrow(() -> repo.deleteAllByIdInBatch(new ArrayList<>())); + } + private BasicTypeData populateData(BasicTypeData basicTypeData) throws MalformedURLException { basicTypeData.setDoubleValue(Math.PI); basicTypeData.setBigDecimalValue(BigDecimal.valueOf(Math.PI * 2.0)); diff --git a/extensions/spring-data-jpa/runtime/src/main/java/io/quarkus/spring/data/runtime/RepositorySupport.java b/extensions/spring-data-jpa/runtime/src/main/java/io/quarkus/spring/data/runtime/RepositorySupport.java index 8588b7223537c..64daa3dceb133 100644 --- a/extensions/spring-data-jpa/runtime/src/main/java/io/quarkus/spring/data/runtime/RepositorySupport.java +++ b/extensions/spring-data-jpa/runtime/src/main/java/io/quarkus/spring/data/runtime/RepositorySupport.java @@ -39,7 +39,37 @@ public static void deleteAll(AbstractJpaOperations> operations, } } + /** + * Add call to the Panache method implementing the actual retrieving of a reference to an entity with the given class and + * identifier. + * + * @param operations an instance of {@code AbstractJpaOperations} used to perform JPA operations + * @param entityClass the {@code Class} object of the entity type to be retrieved + * @param id the identifier of the entity to be retrieved + * @return a reference to the entity of the specified class with the given identifier + * @deprecated use {@link RepositorySupport#getReferenceById)} instead. + */ + @Deprecated public static Object getOne(AbstractJpaOperations> operations, Class entityClass, Object id) { + return getReferenceById(operations, entityClass, id); + } + + /** + * Add call to the Panache method implementing the actual retrieving of a reference to an entity with the given class and + * identifier. + * + * @param operations an instance of {@code AbstractJpaOperations} used to perform JPA operations + * @param entityClass the {@code Class} object of the entity type to be retrieved + * @param id the identifier of the entity to be retrieved + * @return a reference to the entity of the specified class with the given identifier + * @deprecated use {@link RepositorySupport#getReferenceById)} instead. + */ + @Deprecated + public static Object getById(AbstractJpaOperations> operations, Class entityClass, Object id) { + return getReferenceById(operations, entityClass, id); + } + + public static Object getReferenceById(AbstractJpaOperations> operations, Class entityClass, Object id) { return operations.getSession(entityClass).getReference(entityClass, id); }