diff --git a/pom.xml b/pom.xml
index 4a25459fcb..582ee6696e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -246,6 +246,7 @@
spring-zuul
spring-reactor
spring-vertx
+ spring-jinq
spring-rest-embedded-tomcat
diff --git a/spring-jinq/pom.xml b/spring-jinq/pom.xml
new file mode 100644
index 0000000000..a895ae8dd4
--- /dev/null
+++ b/spring-jinq/pom.xml
@@ -0,0 +1,83 @@
+
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+ 4.0.0
+ spring-jinq
+ 0.1-SNAPSHOT
+
+ spring-jinq
+
+ jar
+
+
+ UTF-8
+ 1.8
+
+ 1.8.22
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ 1.5.9.RELEASE
+ pom
+ import
+
+
+
+
+
+
+ org.jinq
+ jinq-jpa
+ ${jinq.version}
+
+
+
+
+ com.h2database
+ h2
+
+
+
+ org.hibernate
+ hibernate-entitymanager
+
+
+
+
+ org.springframework
+ spring-orm
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+ false
+
+
+
+
+
+
diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/JinqApplication.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/JinqApplication.java
new file mode 100644
index 0000000000..d53b585d36
--- /dev/null
+++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/JinqApplication.java
@@ -0,0 +1,12 @@
+package com.baeldung.spring.jinq;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class JinqApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(JinqApplication.class, args);
+ }
+}
diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/config/JinqProviderConfiguration.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/config/JinqProviderConfiguration.java
new file mode 100644
index 0000000000..6d921045b7
--- /dev/null
+++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/config/JinqProviderConfiguration.java
@@ -0,0 +1,18 @@
+package com.baeldung.spring.jinq.config;
+
+import javax.persistence.EntityManagerFactory;
+
+import org.jinq.jpa.JinqJPAStreamProvider;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class JinqProviderConfiguration {
+
+ @Bean
+ @Autowired
+ JinqJPAStreamProvider jinqProvider(EntityManagerFactory emf) {
+ return new JinqJPAStreamProvider(emf);
+ }
+}
diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Car.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Car.java
new file mode 100644
index 0000000000..263e6c7622
--- /dev/null
+++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Car.java
@@ -0,0 +1,58 @@
+package com.baeldung.spring.jinq.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+
+@Entity(name = "CAR")
+public class Car {
+ private String model;
+ private String description;
+ private int year;
+ private String engine;
+ private Manufacturer manufacturer;
+
+ @Id
+ public String getModel() {
+ return model;
+ }
+
+ public void setModel(String model) {
+ this.model = model;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public int getYear() {
+ return year;
+ }
+
+ public void setYear(int year) {
+ this.year = year;
+ }
+
+ public String getEngine() {
+ return engine;
+ }
+
+ public void setEngine(String engine) {
+ this.engine = engine;
+ }
+
+ @OneToOne
+ @JoinColumn(name = "name")
+ public Manufacturer getManufacturer() {
+ return manufacturer;
+ }
+
+ public void setManufacturer(Manufacturer manufacturer) {
+ this.manufacturer = manufacturer;
+ }
+}
diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Manufacturer.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Manufacturer.java
new file mode 100644
index 0000000000..f6e5fd23de
--- /dev/null
+++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Manufacturer.java
@@ -0,0 +1,42 @@
+package com.baeldung.spring.jinq.entities;
+
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+
+@Entity(name = "MANUFACTURER")
+public class Manufacturer {
+
+ private String name;
+ private String city;
+ private List cars;
+
+ @Id
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ @OneToMany(mappedBy = "model")
+ public List getCars() {
+ return cars;
+ }
+
+ public void setCars(List cars) {
+ this.cars = cars;
+ }
+
+}
diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/BaseJinqRepositoryImpl.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/BaseJinqRepositoryImpl.java
new file mode 100644
index 0000000000..42b81ecc59
--- /dev/null
+++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/BaseJinqRepositoryImpl.java
@@ -0,0 +1,26 @@
+package com.baeldung.spring.jinq.repositories;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+import org.jinq.jpa.JPAJinqStream;
+import org.jinq.jpa.JinqJPAStreamProvider;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public abstract class BaseJinqRepositoryImpl {
+ @Autowired
+ private JinqJPAStreamProvider jinqDataProvider;
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ protected abstract Class entityType();
+
+ public JPAJinqStream stream() {
+ return streamOf(entityType());
+ }
+
+ protected JPAJinqStream streamOf(Class clazz) {
+ return jinqDataProvider.streamAll(entityManager, clazz);
+ }
+}
diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepository.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepository.java
new file mode 100644
index 0000000000..56f6106e08
--- /dev/null
+++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepository.java
@@ -0,0 +1,27 @@
+package com.baeldung.spring.jinq.repositories;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.jinq.tuples.Pair;
+import org.jinq.tuples.Tuple3;
+
+import com.baeldung.spring.jinq.entities.Car;
+import com.baeldung.spring.jinq.entities.Manufacturer;
+
+public interface CarRepository {
+
+ Optional findByModel(String model);
+
+ List findByModelAndDescription(String model, String desc);
+
+ List> findWithModelYearAndEngine();
+
+ Optional findManufacturerByModel(String model);
+
+ List> findCarsPerManufacturer();
+
+ long countCarsByModel(String model);
+
+ List findAll(int skip, int limit);
+}
diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepositoryImpl.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepositoryImpl.java
new file mode 100644
index 0000000000..bf16c87461
--- /dev/null
+++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepositoryImpl.java
@@ -0,0 +1,72 @@
+package com.baeldung.spring.jinq.repositories;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.jinq.orm.stream.JinqStream;
+import org.jinq.tuples.Pair;
+import org.jinq.tuples.Tuple3;
+import org.springframework.stereotype.Repository;
+
+import com.baeldung.spring.jinq.entities.Car;
+import com.baeldung.spring.jinq.entities.Manufacturer;
+
+@Repository
+public class CarRepositoryImpl extends BaseJinqRepositoryImpl implements CarRepository {
+
+ @Override
+ public Optional findByModel(String model) {
+ return stream().where(c -> c.getModel()
+ .equals(model))
+ .findFirst();
+ }
+
+ @Override
+ public List findByModelAndDescription(String model, String desc) {
+ return stream().where(c -> c.getModel()
+ .equals(model)
+ && c.getDescription()
+ .contains(desc))
+ .toList();
+ }
+
+ @Override
+ public List> findWithModelYearAndEngine() {
+ return stream().select(c -> new Tuple3<>(c.getModel(), c.getYear(), c.getEngine()))
+ .toList();
+ }
+
+ @Override
+ public Optional findManufacturerByModel(String model) {
+ return stream().where(c -> c.getModel()
+ .equals(model))
+ .select(c -> c.getManufacturer())
+ .findFirst();
+ }
+
+ @Override
+ public List> findCarsPerManufacturer() {
+ return streamOf(Manufacturer.class).join(m -> JinqStream.from(m.getCars()))
+ .toList();
+ }
+
+ @Override
+ public long countCarsByModel(String model) {
+ return stream().where(c -> c.getModel()
+ .equals(model))
+ .count();
+ }
+
+ @Override
+ public List findAll(int skip, int limit) {
+ return stream().skip(skip)
+ .limit(limit)
+ .toList();
+ }
+
+ @Override
+ protected Class entityType() {
+ return Car.class;
+ }
+
+}
diff --git a/spring-jinq/src/main/resources/application.properties b/spring-jinq/src/main/resources/application.properties
new file mode 100644
index 0000000000..dc73bed0c5
--- /dev/null
+++ b/spring-jinq/src/main/resources/application.properties
@@ -0,0 +1,7 @@
+spring.datasource.url=jdbc:h2:~/jinq
+spring.datasource.username=sa
+spring.datasource.password=
+
+spring.jpa.hibernate.ddl-auto=create-drop
+spring.jpa.show-sql=true
+spring.jpa.properties.hibernate.format_sql=true
\ No newline at end of file
diff --git a/spring-jinq/src/test/java/com/baeldung/spring/jinq/repositories/CarRepositoryIntegrationTest.java b/spring-jinq/src/test/java/com/baeldung/spring/jinq/repositories/CarRepositoryIntegrationTest.java
new file mode 100644
index 0000000000..9cb126cbaa
--- /dev/null
+++ b/spring-jinq/src/test/java/com/baeldung/spring/jinq/repositories/CarRepositoryIntegrationTest.java
@@ -0,0 +1,42 @@
+package com.baeldung.spring.jinq.repositories;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import com.baeldung.spring.jinq.JinqApplication;
+
+@ContextConfiguration(classes = JinqApplication.class)
+@RunWith(SpringJUnit4ClassRunner.class)
+public class CarRepositoryIntegrationTest {
+
+ @Autowired
+ private CarRepository repository;
+
+ @Test
+ public void givenACar_whenFilter_thenShouldBeFound() {
+ assertThat(repository.findByModel("model1")
+ .isPresent()).isFalse();
+ }
+
+ @Test
+ public void givenACar_whenMultipleFilters_thenShouldBeFound() {
+ assertThat(repository.findByModelAndDescription("model1", "desc")
+ .isEmpty()).isTrue();
+ }
+
+ @Test
+ public void whenUseASelectClause() {
+ assertThat(repository.findWithModelYearAndEngine()
+ .isEmpty()).isTrue();
+ }
+
+ @Test
+ public void whenUsingOneToOneRelationship() {
+ assertThat(repository.findManufacturerByModel("model1")).isNotNull();
+ }
+}