All Projects → consoleau → Kotlin Jpa Specification Dsl

consoleau / Kotlin Jpa Specification Dsl

Licence: apache-2.0
This library provides a fluent DSL for querying spring data JPA repositories using spring data Specifications (i.e. the JPA Criteria API), without boilerplate code or a generated metamodel.

Programming Languages

kotlin
9241 projects
dsl
153 projects

Projects that are alternatives of or similar to Kotlin Jpa Specification Dsl

Spring-Boot-2
Spring Boot 2.x examples
Stars: ✭ 33 (-83.74%)
Mutual labels:  spring-data, jpa
Spring Data Jpa
Simplifies the development of creating a JPA-based data access layer.
Stars: ✭ 2,238 (+1002.46%)
Mutual labels:  jpa, spring-data
Spring Data Jpa Entity Graph
Spring Data JPA extension allowing full dynamic usage of EntityGraph on repositories
Stars: ✭ 221 (+8.87%)
Mutual labels:  jpa, spring-data
spring-boot-jpa
A Spring Boot microservices reference application using Spring Data JPA
Stars: ✭ 25 (-87.68%)
Mutual labels:  spring-data, jpa
Angularjs Springmvc Sample Boot
A RESTful sample using Spring Boot, Spring MVC, Spring Data and Angular/Bootstrap.
Stars: ✭ 309 (+52.22%)
Mutual labels:  jpa, spring-data
Springboot Registration Login Theperfectexample
Login & Signup tutorial for every website ,mixes a lot of microservices together with the latest spring framework api in combined with full security
Stars: ✭ 89 (-56.16%)
Mutual labels:  jpa, spring-data
spring-boot-java-swing-reservations
The project aims to present how to connect Spring Boot 2 and Java Swing GUI widget toolkit. All application dependencies are provided by Docker Compose. There are also static code analysis tools like FindBugs and Checkstyle.
Stars: ✭ 86 (-57.64%)
Mutual labels:  spring-data, jpa
spring-data-requery
Spring Data with Requery
Stars: ✭ 43 (-78.82%)
Mutual labels:  spring-data, jpa
Atom
Java course materials
Stars: ✭ 293 (+44.33%)
Mutual labels:  jpa, spring-data
Hibernate Springboot
Collection of best practices for Java persistence performance in Spring Boot applications
Stars: ✭ 589 (+190.15%)
Mutual labels:  jpa, spring-data
Spring Data Examples
Examples for using Spring Data for JPA, MongoDB, Neo4j, Redis
Stars: ✭ 181 (-10.84%)
Mutual labels:  jpa, spring-data
Minidao
轻量级JAVA持久层,类似Mybatis一样的用法,基于SpringJdbc实现更轻量
Stars: ✭ 177 (-12.81%)
Mutual labels:  jpa
Graphql Jpa
JPA Implementation of GraphQL (builds on graphql-java)
Stars: ✭ 156 (-23.15%)
Mutual labels:  jpa
Spring Data Jpa Reference Documentation
Spring Data JPA 参考指南 中文版
Stars: ✭ 154 (-24.14%)
Mutual labels:  jpa
Spring Content
Cloud-Native Storage and Enterprise Content Services (ECMS) for Spring
Stars: ✭ 151 (-25.62%)
Mutual labels:  spring-data
Jpa Hibernate Tutorials
Hibernate Tutorials with Spring Boot and Spring-Data-JPA
Stars: ✭ 186 (-8.37%)
Mutual labels:  jpa
Okta Spring Boot React Crud Example
Simple CRUD with React and Spring Boot 2.0
Stars: ✭ 176 (-13.3%)
Mutual labels:  jpa
Spring Backend Boilerplate
The modularized backend boilerplate based on Spring Boot Framework, easy to get started and add your business part.
Stars: ✭ 134 (-33.99%)
Mutual labels:  spring-data
Jersey Jwt
Example of REST API with JWT authentication using Jersey, Jackson, Undertow, Weld, Hibernate and Arquillian.
Stars: ✭ 131 (-35.47%)
Mutual labels:  jpa
Ebook Chat App Spring Websocket Cassandra Redis Rabbitmq
Pro Java Clustering and Scalability: Building Real-Time Apps with Spring, Cassandra, Redis, WebSocket and RabbitMQ
Stars: ✭ 186 (-8.37%)
Mutual labels:  spring-data

Spring Data JPA Specification DSL for Kotlin

Build Status License Download

This library provides a fluent DSL for querying spring data JPA repositories using spring data Specifications (i.e. the JPA Criteria API), without boilerplate code or a generated metamodel.

Hat tip to Mike Buhot for the initial implementation.

Quick Start

repositories {
    jcenter()
}

dependencies {
    compile("au.com.console:kotlin-jpa-specification-dsl:2.0.0")
}

Example

import au.com.console.jpaspecificationdsl.*   // 1. Import Kotlin magic

////
// 2. Declare JPA Entities
@Entity
data class TvShow(
    @Id
    @GeneratedValue
    val id: Int = 0,
    val name: String = "",
    val synopsis: String = "",
    val availableOnNetflix: Boolean = false,
    val releaseDate: String? = null,
    @OneToMany(cascade = arrayOf(javax.persistence.CascadeType.ALL))
    val starRatings: Set<StarRating> = emptySet())

@Entity
data class StarRating(
    @Id
    @GeneratedValue
    val id: Int = 0,
    val stars: Int = 0)


////
// 3. Declare JPA Repository with JpaSpecificationExecutor
@Repository
interface TvShowRepository : CrudRepository<TvShow, Int>, JpaSpecificationExecutor<TvShow>


////
// 4. Kotlin Properties are now usable to create fluent specifications
@Service
class MyService @Inject constructor(val tvShowRepo: TvShowRepository) {
   fun findShowsReleasedIn2010NotOnNetflix(): List<TvShow> {
     return tvShowRepo.findAll(TvShow::availableOnNetflix.isFalse() and TvShow::releaseDate.equal("2010"))
   }

   /* Fall back to spring API with some extra helpers for more complex join queries */
   fun findShowsWithComplexQuery(): List<TvShow> {
       return tvShowRepo.findAll(where { equal(it.join(TvShow::starRatings).get(StarRating::stars), 2) })
   }
}

Advanced Usage

For more complex and dynamic queries it's good practice to create functions that use the DSL to make queries more readable, and to allow for their composition in complex dynamic queries.

fun hasName(name: String?): Specification<TvShow>? = name?.let {
    TvShow::name.equal(it)
}

fun availableOnNetflix(available: Boolean?): Specification<TvShow>? = available?.let {
    TvShow::availableOnNetflix.equal(it)
}

fun hasReleaseDateIn(releaseDates: List<String>?): Specification<TvShow>? = releaseDates?.let {
    TvShow::releaseDate.`in`(releaseDates)
}

fun hasKeywordIn(keywords: List<String>?): Specification<TvShow>? = keywords?.let {
    or(keywords.map(::hasKeyword))
}

fun hasKeyword(keyword: String?): Specification<TvShow>? = keyword?.let {
    TvShow::synopsis.like("%$keyword%")
}

These functions can be combined with and() and or() for complex nested queries:

    val shows = tvShowRepo.findAll(
            or(
                    and(
                            availableOnNetflix(false),
                            hasKeywordIn(listOf("Jimmy"))
                    ),
                    and(
                            availableOnNetflix(true),
                            or(
                                    hasKeyword("killer"),
                                    hasKeyword("monster")
                            )
                    )
            )
    )

Or they can be combined with a service-layer query DTO and mapping extension function

    /**
     * A TV show query DTO - typically used at the service layer.
     */
    data class TvShowQuery(
            val name: String? = null,
            val availableOnNetflix: Boolean? = null,
            val keywords: List<String> = listOf(),
            val releaseDates: List<String> = listOf()
    )

    /**
     * A single TvShowQuery is equivalent to an AND of all supplied criteria.
     * Note: any criteria that is null will be ignored (not included in the query).
     */
    fun TvShowQuery.toSpecification(): Specification<TvShow> = and(
            hasName(name),
            availableOnNetflix(availableOnNetflix),
            hasKeywordIn(keywords),
            hasReleaseDateIn(releaseDates)
    )

for powerful dynamic queries:

    val query = TvShowQuery(availableOnNetflix = false, keywords = listOf("Rick", "Jimmy"))
    val shows = tvShowRepo.findAll(query.toSpecification())

For more details, refer to JPASpecificationDSLTest.kt in the unit tests.

How it works

This DSL builds on Spring Data's Specifications abstraction, sprinkling some Kotlin sugar over it to remove the boilerplate and the need to generate a metamodel.

The code TvShow::releaseDate.equal("2010") is a call to the Kotlin extension function:

fun <T, R> KProperty1<T, R?>.equal(x: R): Specification<T> = spec { equal(it, x) }

This is a bit dense, but makes sense when it's broken down:

  • T: The type of the object that the property is declared on, in this case TvShow
  • R: The property type, for TvShow::releaseDate it is String
  • KProperty1<T,R?>: Kotlin reflection API representation of the property TvShow::releaseDate. The 1 refers to a property with 1 receiver, and R? is declared as nullable for the method to work on nullable properties as well as non-null properties.
  • x: The value to test against
  • Specification<T>: The Spring data specifications result

This is implemented using a private helper function spec that captures the common use case of taking an Entity property, and using a CriteriaBuilder to create a Predicate:

private fun <T, R> KProperty1<T, R?>.spec(makePredicate: CriteriaBuilder.(path: Path<R>) -> Predicate): Specification<T> =
    this.let { property -> where { root -> makePredicate(root.get(property)) } }

This uses the where factory method, which expects a callback with the signature: CriteriaBuilder.(Root<T>) -> Predicate

The code converts a KProperty1<T,R> to a Path<T> using root.get<R>(property).

Once it has a Path<R> to work with, it delegates to the makePredicate function to configure the CriteriaBuilder given the Path.

The makePredicate function passed to spec is an extension function on CriteraiBuilder. So when equal(it, x) is called from inside the spec block, it is invoking CriteriaBuilder::equal.

Contributing to the Project

If you'd like to contribute code to this project you can do so through GitHub by forking the repository and generating a pull request.

By contributing your code, you agree to license your contribution under the terms of the Apache License v2.0.

License

Copyright 2016 RES INFORMATION SERVICES PTY LTD

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].