diff --git a/README.md b/README.md index 9890b49..1ccd8cd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # specification-with-projection Support Projections with `JpaSpecificationExecutor.findAll(Specification,Pageable)` for Spring Data JPA +>version 3.x.x for Spring Data JPA 3.x (Spring Boot 3.x) + >version 2.x.x for Spring Data JPA 2.x (Spring Boot 2.x) >version 1.x.x Spring Data JPA 1.x @@ -8,6 +10,14 @@ Support Projections with `JpaSpecificationExecutor.findAll(Specification,Pageabl ## How to use * add dependency to pom ```xml + + + th.co.geniustree.springdata.jpa + specification-with-projections + 3.0.0 + +``` +```xml th.co.geniustree.springdata.jpa diff --git a/pom.xml b/pom.xml index d24b119..8889684 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 th.co.geniustree.springdata.jpa @@ -13,14 +14,15 @@ org.springframework.boot spring-boot-starter-parent - 2.5.1 - + 3.1.5 + UTF-8 UTF-8 - 1.8 + 17 + 17 @@ -73,12 +75,13 @@ org.hibernate hibernate-jpamodelgen + 6.3.1.Final provided org.projectlombok lombok - 1.18.4 + 1.18.30 provided @@ -112,7 +115,7 @@ org.apache.maven.plugins maven-source-plugin - 3.0.1 + 3.3.0 attach-sources @@ -125,7 +128,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.4 + 3.6.0 attach-javadocs @@ -138,7 +141,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.6 + 3.1.0 sign-artifacts diff --git a/src/main/java/org/springframework/data/repository/query/TupleConverter.java b/src/main/java/org/springframework/data/repository/query/TupleConverter.java index a32a112..abd873b 100644 --- a/src/main/java/org/springframework/data/repository/query/TupleConverter.java +++ b/src/main/java/org/springframework/data/repository/query/TupleConverter.java @@ -4,8 +4,8 @@ import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import javax.persistence.Tuple; -import javax.persistence.TupleElement; +import jakarta.persistence.Tuple; +import jakarta.persistence.TupleElement; import java.util.*; import java.util.stream.Collectors; diff --git a/src/main/java/th/co/geniustree/springdata/jpa/repository/JpaSpecificationExecutorWithProjection.java b/src/main/java/th/co/geniustree/springdata/jpa/repository/JpaSpecificationExecutorWithProjection.java index 2e2a3e4..5adbc83 100644 --- a/src/main/java/th/co/geniustree/springdata/jpa/repository/JpaSpecificationExecutorWithProjection.java +++ b/src/main/java/th/co/geniustree/springdata/jpa/repository/JpaSpecificationExecutorWithProjection.java @@ -17,7 +17,7 @@ public interface JpaSpecificationExecutorWithProjection { Optional findById(ID id, Class projectionClass); - + Optional findOne(Specification spec, Class projectionClass); Page findAll(Specification spec, Class projectionClass, Pageable pageable); diff --git a/src/main/java/th/co/geniustree/springdata/jpa/repository/support/DefaultQueryHints.java b/src/main/java/th/co/geniustree/springdata/jpa/repository/support/DefaultQueryHints.java index 6e9fb0a..55e6d32 100644 --- a/src/main/java/th/co/geniustree/springdata/jpa/repository/support/DefaultQueryHints.java +++ b/src/main/java/th/co/geniustree/springdata/jpa/repository/support/DefaultQueryHints.java @@ -25,7 +25,7 @@ import org.springframework.data.util.Optionals; import org.springframework.util.Assert; -import javax.persistence.EntityManager; +import jakarta.persistence.EntityManager; import java.util.*; import java.util.function.BiConsumer; diff --git a/src/main/java/th/co/geniustree/springdata/jpa/repository/support/JpaSpecificationExecutorWithProjectionImpl.java b/src/main/java/th/co/geniustree/springdata/jpa/repository/support/JpaSpecificationExecutorWithProjectionImpl.java index 81995b7..1897b89 100644 --- a/src/main/java/th/co/geniustree/springdata/jpa/repository/support/JpaSpecificationExecutorWithProjectionImpl.java +++ b/src/main/java/th/co/geniustree/springdata/jpa/repository/support/JpaSpecificationExecutorWithProjectionImpl.java @@ -20,24 +20,24 @@ import org.springframework.data.repository.query.ReturnTypeWarpper; import org.springframework.data.repository.query.ReturnedType; import org.springframework.data.repository.query.TupleConverter; -import org.springframework.data.repository.support.PageableExecutionUtils; +import org.springframework.data.support.PageableExecutionUtils; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import th.co.geniustree.springdata.jpa.repository.JpaSpecificationExecutorWithProjection; -import javax.persistence.*; -import javax.persistence.criteria.*; -import javax.persistence.metamodel.Attribute; -import javax.persistence.metamodel.Bindable; -import javax.persistence.metamodel.ManagedType; -import javax.persistence.metamodel.PluralAttribute; +import jakarta.persistence.*; +import jakarta.persistence.criteria.*; +import jakarta.persistence.metamodel.Attribute; +import jakarta.persistence.metamodel.Bindable; +import jakarta.persistence.metamodel.ManagedType; +import jakarta.persistence.metamodel.PluralAttribute; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Member; import java.util.*; -import static javax.persistence.metamodel.Attribute.PersistentAttributeType.*; +import static jakarta.persistence.metamodel.Attribute.PersistentAttributeType.*; /** @@ -68,11 +68,11 @@ public JpaSpecificationExecutorWithProjectionImpl(JpaEntityInformation entityInf this.entityManager = entityManager; this.entityInformation = entityInformation; } - + @Override public Optional findById(ID id, Class projectionType) { final ReturnedType returnedType = ReturnTypeWarpper.of(projectionType, getDomainClass(), projectionFactory); - + CriteriaBuilder builder = this.entityManager.getCriteriaBuilder(); CriteriaQuery q = builder.createQuery(Tuple.class); Root root = q.from(getDomainClass()); @@ -90,9 +90,9 @@ public Optional findById(ID id, Class projectionType) { } else { throw new IllegalArgumentException("only except projection"); } - + final TypedQuery query = this.applyRepositoryMethodMetadata(this.entityManager.createQuery(q)); - + try { final MyResultProcessor resultProcessor = new MyResultProcessor(projectionFactory,returnedType); final R singleResult = resultProcessor.processResult(query.getSingleResult(), new TupleConverter(returnedType)); diff --git a/src/test/java/th/co/geniustree/springdata/jpa/SpecificationExecutorProjectionTest.java b/src/test/java/th/co/geniustree/springdata/jpa/SpecificationExecutorProjectionTest.java index b78f130..54bd10c 100644 --- a/src/test/java/th/co/geniustree/springdata/jpa/SpecificationExecutorProjectionTest.java +++ b/src/test/java/th/co/geniustree/springdata/jpa/SpecificationExecutorProjectionTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -19,6 +20,7 @@ @ExtendWith(SpringExtension.class) @DataJpaTest @Transactional +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) public class SpecificationExecutorProjectionTest { @Autowired private DocumentRepository documentRepository; @@ -27,7 +29,7 @@ public class SpecificationExecutorProjectionTest { @Test public void findAll() { Specification where = Specification.where(DocumentSpecs.idEq(1L)); - Page all = documentRepository.findAll(where, DocumentRepository.DocumentWithoutParent.class, PageRequest.of(0,10)); + Page all = documentRepository.findAll(where, DocumentRepository.DocumentWithoutParent.class, PageRequest.of(0, 10)); Assertions.assertThat(all).isNotEmpty(); Assertions.assertThat(all.getContent().get(0).getDocumentType()).isEqualTo("ต้นฉบับ"); } @@ -35,7 +37,7 @@ public void findAll() { @Test public void findAll2() { Specification where = Specification.where(DocumentSpecs.idEq(1L)); - Page all = documentRepository.findAll(where, DocumentRepository.DocumentWithoutParent.class, PageRequest.of(0,10)); + Page all = documentRepository.findAll(where, DocumentRepository.DocumentWithoutParent.class, PageRequest.of(0, 10)); Assertions.assertThat(all).isNotEmpty(); Assertions.assertThat(all.getContent().get(0).getChild().size()).isEqualTo(1); } @@ -43,7 +45,7 @@ public void findAll2() { @Test public void findAll3() { Specification where = Specification.where(DocumentSpecs.idEq(1L)); - Page all = documentRepository.findAll(where, DocumentRepository.OnlyId.class, PageRequest.of(0,10)); + Page all = documentRepository.findAll(where, DocumentRepository.OnlyId.class, PageRequest.of(0, 10)); Assertions.assertThat(all).isNotEmpty(); Assertions.assertThat(all.getContent().get(0).getId()).isEqualTo(1L); } @@ -51,7 +53,7 @@ public void findAll3() { @Test public void findAll4() { Specification where = Specification.where(DocumentSpecs.idEq(24L)); - Page all = documentRepository.findAll(where, DocumentRepository.DocumentWithoutParent.class, PageRequest.of(0,10)); + Page all = documentRepository.findAll(where, DocumentRepository.DocumentWithoutParent.class, PageRequest.of(0, 10)); Assertions.assertThat(all).isNotEmpty(); Assertions.assertThat(all.getContent().get(0).getChild()).isNull(); } @@ -59,14 +61,15 @@ public void findAll4() { @Test public void findAll5() { Specification where = Specification.where(DocumentSpecs.idEq(24L)); - Page all = documentRepository.findAll(where, DocumentRepository.OnlyParent.class, PageRequest.of(0,10)); + Page all = documentRepository.findAll(where, DocumentRepository.OnlyParent.class, PageRequest.of(0, 10)); Assertions.assertThat(all).isNotEmpty(); Assertions.assertThat(all.getContent().get(0).getParent().getId()).isEqualTo(13L); } + @Test public void find_single_page() { Specification where = Specification.where(DocumentSpecs.idEq(24L)); - Page all = documentRepository.findAll(where, DocumentRepository.OnlyParent.class, PageRequest.of(0,10)); + Page all = documentRepository.findAll(where, DocumentRepository.OnlyParent.class, PageRequest.of(0, 10)); Assertions.assertThat(all).isNotEmpty(); Assertions.assertThat(all.getTotalElements()).isEqualTo(1); Assertions.assertThat(all.getTotalPages()).isEqualTo(1); @@ -75,7 +78,7 @@ public void find_single_page() { @Test public void find_all_page() { Specification where = Specification.where(null); - Page all = documentRepository.findAll(where, DocumentRepository.OnlyParent.class, PageRequest.of(0,10)); + Page all = documentRepository.findAll(where, DocumentRepository.OnlyParent.class, PageRequest.of(0, 10)); Assertions.assertThat(all).isNotEmpty(); Assertions.assertThat(all.getTotalElements()).isEqualTo(24); Assertions.assertThat(all.getTotalPages()).isEqualTo(3); @@ -87,13 +90,13 @@ public void findOne() { Optional one = documentRepository.findOne(where, DocumentRepository.DocumentWithoutParent.class); Assertions.assertThat(one.get().getDocumentType()).isEqualTo("ต้นฉบับ"); } - + @Test public void findBydId() { Optional one = documentRepository.findById(1L, DocumentRepository.DocumentWithoutParent.class); Assertions.assertThat(one.get().getDocumentType()).isEqualTo("ต้นฉบับ"); } - + @Test public void findOneWithOpenProjection() { Specification where = Specification.where(DocumentSpecs.idEq(1L)); @@ -104,7 +107,7 @@ public void findOneWithOpenProjection() { @Test public void findAllWithOpenProjection() { Specification where = Specification.where(DocumentSpecs.idEq(1L)); - Page page = documentRepository.findAll(where, DocumentRepository.OpenProjection.class,PageRequest.of(0,10)); + Page page = documentRepository.findAll(where, DocumentRepository.OpenProjection.class, PageRequest.of(0, 10)); Assertions.assertThat(page.getContent().get(0).getDescriptionString()).isEqualTo("descriptiontest"); } diff --git a/src/test/java/th/co/geniustree/springdata/jpa/domain/Document.java b/src/test/java/th/co/geniustree/springdata/jpa/domain/Document.java index e88cf40..ea7dab6 100644 --- a/src/test/java/th/co/geniustree/springdata/jpa/domain/Document.java +++ b/src/test/java/th/co/geniustree/springdata/jpa/domain/Document.java @@ -1,6 +1,6 @@ package th.co.geniustree.springdata.jpa.domain; -import javax.persistence.*; +import jakarta.persistence.*; import java.io.Serializable; import java.util.List; import java.util.Objects; diff --git a/src/test/java/th/co/geniustree/springdata/jpa/domain/FormType.java b/src/test/java/th/co/geniustree/springdata/jpa/domain/FormType.java index e5b280f..3f099eb 100644 --- a/src/test/java/th/co/geniustree/springdata/jpa/domain/FormType.java +++ b/src/test/java/th/co/geniustree/springdata/jpa/domain/FormType.java @@ -1,6 +1,7 @@ package th.co.geniustree.springdata.jpa.domain; -import javax.persistence.*; +import jakarta.persistence.*; + import java.io.Serializable; /** diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties index 7631a18..dc7c074 100644 --- a/src/test/resources/application.properties +++ b/src/test/resources/application.properties @@ -1,10 +1,10 @@ ################## JPA spring.jpa.hibernate.ddl-auto=create-drop spring.jpa.properties.hibernate.cache.use_second_level_cache=false -spring.jpa.hibernate.use-new-id-generator-mappings=true +spring.jpa.properties.hibernate.id.new_generator_mappings=true spring.sql.init.mode=always ################## spring.datasource -spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_ON_EXIT=FALSE +spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_ON_EXIT=FALSE;MODE=LEGACY # spring.datasource.username=sa # spring.datasource.password=sa spring.datasource.driver-class-name=org.h2.Driver diff --git a/src/test/resources/import.sql b/src/test/resources/import.sql index b2cbb7e..dd14ad2 100644 --- a/src/test/resources/import.sql +++ b/src/test/resources/import.sql @@ -1,9 +1,9 @@ -insert into form_type values('01', 'ก.01'); -insert into form_type values('04', 'ก.04'); -insert into form_type values('05', 'ก.05'); -insert into form_type values('06', 'ก.06'); -insert into form_type values('07', 'ก.07'); -insert into form_type values('08', 'ก.08'); +insert into form_type (id, form_desc) values('01', 'ก.01'); +insert into form_type (id, form_desc) values('04', 'ก.04'); +insert into form_type (id, form_desc) values('05', 'ก.05'); +insert into form_type (id, form_desc) values('06', 'ก.06'); +insert into form_type (id, form_desc) values('07', 'ก.07'); +insert into form_type (id, form_desc) values('08', 'ก.08'); insert into document (id, description, category, type, FLAG_HAS_SUB, FORM_TYPE_ID) values(DOCUMENT_SEQ.nextVal, 'descriptiontest', 'ก.01', 'ต้นฉบับ', 'false', '01'); insert into document (id, description, category, type, FLAG_HAS_SUB, FORM_TYPE_ID) values(DOCUMENT_SEQ.nextVal, 'description', 'ก.01', 'ต้นฉบับ', 'true', '01');