Jinq is a library that provides support for database queries in Java. It is inspired by .NET’s LINQ. A developer can use Java Stream API, standard functions (e.g. , ), and relational, arithmetic and logical operators (e.g. ==, <, +, /, &&, ==) for filtering data. String#contains Math#abs List<Book> books = jinqDataProvider.streamAll(entityManager, Book.class) .where(book -> book.getPages() > && book.isPublished()).toList(); 50 In this example, the is not a generated metamodel but a JPA entity class. It looks like magic. Under the hood, Jinq uses lambda serialization and bytecode analysis. Let's start looking at Jinq with a Spring Boot example. Book Dependencies Add the following dependencies in the build.gradle file: implementation implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 'org.jinq:jinq-jpa:1.8.32' Entity classes Consider the example with two tables in the database: and . Add the entity classes: books authors (name = ) { (strategy = GenerationType.IDENTITY) Long id; String title; published; Integer pages; (name = ) Author author; } @Entity "books" public class Book @Id @GeneratedValue private private private boolean private @ManyToOne @JoinColumn "author_id" private // getters and setters (name = ) { (strategy = GenerationType.IDENTITY) Long id; String firstName; String lastName; (mappedBy = , cascade = CascadeType.ALL, orphanRemoval = ) ( ) Set<Book> books = LinkedHashSet<>(); } @Entity "authors" public class Author @Id @GeneratedValue private private private @OneToMany "author" true @OrderBy "id" private final new // getters and setters Configuration and Helper We need to create a bean for using Jinq. JinqJPAStreamProvider { { JinqJPAStreamProvider(emf); } } @Configuration public class JinqProviderConfiguration @Bean JinqJPAStreamProvider jinqDataProvider (EntityManagerFactory emf) return new We need to use the method for creating streams. Let's add a helper class. JinqJPAStreamProvider#streamAll { EntityManager entityManager; JinqJPAStreamProvider jinqDataProvider; { .jinqDataProvider = jinqDataProvider; } <T> { jinqDataProvider.streamAll(entityManager, clazz); } } @Component public class JinqHelper @PersistenceContext private private final public JinqHelper (JinqJPAStreamProvider jinqDataProvider) this public JPAJinqStream<T> stream (Class<T> clazz) return Now we are ready to query the database. Query Examples We can use the method to get the number of all authors. count authorsCount = jinqHelper.stream(Author.class).count(); long Let's retrieve all published books that have more than 50 pages. List<Book> books = jinqHelper.stream(Book.class).where(book -> book.getPages() > && book.isPublished()).toList(); 50 If we want to read-only specific columns, we can use the method and the or , ..., classes in the package. select Pair Tuple3 Tuple8 org.jinq.tuples List<Pair<String, String>> allAuthors = jinqHelper.stream(Author.class) .where(author -> author.getFirstName().equals( )) .select(author -> Pair<>(author.getFirstName(), author.getLastName())) .toList(); (Pair<String, String> author : allAuthors) { String firstName = author.getOne(); String lastName = author.getTwo(); } "Simon" new for // ... Jinq provides aggregation methods. Double avgPages = jinqHelper.stream(Book.class).avg(Book::getPages); We can use the method to perform join-queries. We also use the class in the following example joinList Pair List<Pair<Author, Book>> joinedList = jinqHelper.stream(Author.class) .where(author -> author.getFirstName().equals( )) .joinList(Author::getBooks) .where(pair -> pair.getTwo().isPublished()) .toList(); "Simon" Advanced Features Jinq also provides support for grouping, sorting, different types of joins, subqueries, registering your own functions, and other useful features. Conclusion Jinq provides a convenient and natural way to build type-safe database queries. It is easier to use than JPA 1 Criteria API and does not require code generation as Query DSL or JPA 2 metamodel.