[Java - Crnk] Crnk Spring Boot JPA example to expose JPA entities as JSON:API repositories

Crnk Spring Boot JPA example

The Crnk JPA module allows to automatically expose JPA entities as JSON:API repositories. No implementation or Crnk-specific annotations are necessary.

The feature set includes:

  • expose JPA entities to JSON:API repositories

  • expose JPA relations as JSON:API repositories

  • decide which entities to expose as endpoints

  • sorting, filtering, paging, inclusion of related resources.

  • all default operators of crnk are supported: EQ, NEQ, LIKE, LT, LE, GT, GE.

  • filter, sort and include parameters can make use of the dot notation to join to related entities. For example, sort=-project.name,project.id, filter[project.name][NEQ]=someValue or include=project.tasks.

  • support for entity inheritance by allowing sorting, filtering and inclusions to refer to attributes on subtypes.

  • support for Jackson annotations to customize entity attributes on the JSON:API layer, see here.

  • DTO mapping support to map entities to DTOs before sending them to clients.

  • JPA Criteria API and QueryDSL support to issue queries.

  • filter API to intercept and modify issued queries.

  • support for computed attributes behaving like regular, persisted attributes.

  • automatic transaction handling spanning requests and doing a rollback in case of an exception.

  • OptimisticLockExceptionMapper mapped to JSON:API errors with 409 status code.

  • PersistenceException and RollbackException are unwrapped to the usually more interesting exceptions like ValidationException and then translated to JSON:API errors.

Not yet supported are sparse field sets queried by tuple queries.

Example

The following gives a brief example of how to setup Crnk with Spring Boot and JPA.

build.gradle

Add Crank dependencies to bundle.gradle.

Remember to make org.springframework.boot and org.springframework.boot:spring-boot-dependencies have the same version.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// build.gradle

plugins {
id 'org.springframework.boot' version '2.6.2'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
id 'org.springframework.experimental.aot' version '0.11.1'
}

group = 'com.cloudolife.common.configuration.service'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

configurations {
compileOnly {
extendsFrom annotationProcessor
}
}

repositories {
maven { url 'https://repo.spring.io/release' }
mavenCentral()
+ jcenter()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
+
+ implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
+
developmentOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'

+ implementation 'io.crnk:crnk-setup-spring-boot2'
+ implementation 'io.crnk:crnk-format-plain-json'
+ implementation 'io.crnk:crnk-home'
+ implementation 'io.crnk:crnk-data-jpa'
+
+ implementation 'org.junit.jupiter:junit-jupiter-api:5.5.1'
}

test {
useJUnitPlatform()
}

+ bootBuildImage {
+ builder = 'paketobuildpacks/builder:tiny'
+ environment = ['BP_NATIVE_IMAGE': 'true']
+ }
+
+ dependencyManagement {
+ imports {
+ mavenBom 'org.springframework.boot:spring-boot-dependencies:2.6.2'
+ mavenBom "io.crnk:crnk-bom:3.4.20210509072026"
+ }
+ }

JsonApiResource - Project.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// Project.java

package io.crnk.example.springboot.microservice;

import javax.persistence.*;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.crnk.core.resource.annotations.JsonApiId;
import io.crnk.core.resource.annotations.JsonApiResource;

@Entity
@Table(name="projects")
@JsonApiResource(type = "projects")
public class Project {

@Id
@JsonApiId
private Long id;

@JsonProperty
private String name;

public Project() {
}

public Project(Long id, String name) {
this.id = id;
this.name = name;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

Repository - ProjectRepositoryImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ProjectRepositoryImpl.java

package io.crnk.example.springboot.microservice;

import io.crnk.data.jpa.JpaEntityRepositoryBase;
import org.springframework.stereotype.Component;

@Component
public class ProjectRepositoryImpl extends JpaEntityRepositoryBase<Project, Long> {

public ProjectRepositoryImpl() {
super(Project.class);
}
}

SpringBootApplication - MinimalSpringBootApplication.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// MinimalSpringBootApplication.java

package io.crnk.example.springboot.microservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;

@Configuration
@SpringBootApplication
public class MinimalSpringBootApplication {

public static void main(String[] args) {
SpringApplication.run(MinimalSpringBootApplication.class, args);
System.out.println("visit http://127.0.0.1:8080/ in your browser");
}
}

Configuration - application.properties

1
2
3
4
5
6
7
8
9
10
11
# application.properties

# Common Application Properties
# https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect

# spring.datasource
spring.datasource.url=jdbc:postgresql://postgres:5432/<Your Database>
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.username=<Your Database UserName>
spring.datasource.password=<Your Database Passowrd>

References

[1] Crnk: Resource-oriented Rest Development with JSON:API - http://www.crnk.io/

[2] Crnk Documentation - http://www.crnk.io/releases/stable/documentation/

[3] Getting Started | Accessing Data with JPA - https://spring.io/guides/gs/accessing-data-jpa/

[4] JSON:API — Latest Specification (v1.0) - https://jsonapi.org/format/

[5] JSON:API — Recommendations - https://jsonapi.org/recommendations/

[6] Spring Boot - https://spring.io/projects/spring-boot

[7] Spring | Spring Quickstart Guide - https://spring.io/quickstart

[8] 3.7. Integration with Spring and Spring Boot | Crnk Documentation - http://www.crnk.io/releases/stable/documentation/#_integration_with_spring_and_spring_boot

[9] 11.2. JPA | Crnk Documentation - http://www.crnk.io/releases/stable/documentation/#_jpa