JPA data provider framework providing reusable data retrieval and persistence interface and mapping layer between consumer and data repository/entities
- Java 21
- Spring Boot 3
implementation("io.opengood.data:jpa-data-provider:VERSION")<dependency>
<groupId>io.opengood.data</groupId>
<artifactId>jpa-data-provider</artifactId>
<version>VERSION</version>
</dependency>Note: See Release version badge above for latest version.
Test data is stored in a Postgres database. A local database is used for testing and local development.
Flyway is used to perform database DDL and DML changes to the database.
To create database service account, copy create_database_user.sql from
Vault to migrations and run:
psql postgres -f migrations/create_database_user.sqlTo create database, run:
psql postgres -f migrations/create_database.sqlTo deploy database schema, copy gradle-default.properties from
Vault to project root and run:
./gradlew flywayMigrate -PenvironmentName=defaultWhen developing REST APIs with data retrieval and persistence to a JPA-enabled data repository, one typically has to write boilerplate code mapping a model to an entity object.
The JPA Data Provider framework providers a simple means to
automatically perform data retrieval and persistence using a common
interface from mappings defined in a special JpaDataProvider<T, Id>
class implementation.
Supported methods:
deletedeleteByIdsexistsgetsave
Simply define the mappings and have the data provider take care of the rest:
@Entity(name = "products")
data class Entity(
@Id
val id: UUID?,
val name: String?,
val sku: String?,
val category: String?
)@Repository
interface DataRepository : JpaRepository<Entity, UUID>@Component
class DataProvider(
override val repository: DataRepository
) : JpaDataProvider<Entity, UUID> {
override val name: String = "products"
override val id: String = "id"
override val mappings: Map<String, String> =
mapOf(
"product_id" to "id",
"product_name" to "name",
"product_sku" to "sku",
"product_category" to "category"
)
override fun idConverter(id: Any): UUID {
return convertToUuid(id)!!
}
override fun filterMapper(filters: Map<String, Any>): Entity =
Entity(
id = nullableObjectFieldValue("id", filters, convertToUuid),
name = nullableObjectFieldValue("name", filters, convertToString),
sku = nullableObjectFieldValue("sku", filters, convertToString),
category = nullableObjectFieldValue("category", filters, convertToString)
)
override fun objectFieldMapper(row: Map<String, Any>): Entity =
Entity(
id = objectFieldValue("id", row, Uuid.empty, convertToUuid),
name = objectFieldValue("name", row, String.empty, convertToString),
sku = objectFieldValue("sku", row, String.empty, convertToString),
category = objectFieldValue("category", row, String.empty, convertToString)
)
override fun rowColumnMapper(o: Entity): Map<String, Any> {
val map = mutableMapOf<String, Any>()
with(map) {
putIfNotAbsent(rowColumnValue("id", o.id, Uuid.empty, convertFromUuid))
putIfNotAbsent(rowColumnValue("name", o.name, String.empty, convertToString))
putIfNotAbsent(rowColumnValue("sku", o.sku, String.empty, convertToString))
putIfNotAbsent(rowColumnValue("category", o.category, String.empty, convertToString))
}
return map
}
}nameis the name of the data provideridis the name of the entity class@Idfieldmappingsprovides the mappings from the consumer model to the entity class via aMap<String, Any>keyis the consumer model field namevalueis the entity class field name
idConverterprovides a function to convert an identifier value to an entity class@Idfield data typefilterMapperprovides the filters available used to filter dataobjectFieldMapperconstructs an entity class from a row of datarowColumnMapperconstructs a row of data from an entity class
Converter functions are provided to allow common data types of Any and
String to be converted to and from explicit entity object field class
types.
The following functions are supported:
| Function | Description | Input Type | Output Type |
|---|---|---|---|
convertFromBigDecimal |
Converts from BigDecimal | BigDecimal |
String |
convertFromBoolean |
Converts from Boolean | Boolean |
String |
convertFromDate |
Converts from SQL Date | java.sql.Date |
String |
convertFromDouble |
Converts from Double | Double |
String |
convertFromFloat |
Converts from Float | Float |
String |
convertFromInt |
Converts from Integer | Integer |
String |
convertFromLong |
Converts from Long | Long |
String |
convertFromShort |
Converts from Short | Short |
String |
convertFromTimestamp |
Converts from SQL Timestamp | java.sql.Timestamp |
String |
convertFromUuid |
Converts from UUID | UUID |
String |
convertToBigDecimal |
Converts to BigDecimal | Any |
BigDecimal |
convertToBoolean |
Converts to Boolean | Any |
Boolean |
convertToDate |
Converts to SQL Date | Any |
java.sql.Date |
convertToDouble |
Converts to Double | Any |
Double |
convertToFloat |
Converts to Float | Any |
Float |
convertToInt |
Converts to Integer | Any |
Integer |
convertToLong |
Converts to Long | Any |
Long |
convertToShort |
Converts to Short | Any |
Short |
convertToString |
Converts to String | Any |
String |
convertToTimestamp |
Converts to SQL Timestamp | Any |
java.sql.Timestamp |
convertToUuid |
Converts to UUID | Any |
UUID |
Data contracts for retrieving data. Includes filtering, paging, and sorting.
Data in JSON format:
filters: List of parameters representing fields, values, and types in which to filter data from data repositoryparams: Filtering parameters in which to filter dataname: Name of field in which to filter datavalue: Filter value for fieldtype: Filter type for fieldEQUALSperforms equality filter on fieldCONTAINSperforms contains filter on field
condition: Filter condition for fieldANDcreates an and condition for fieldORcreates an or condition for field
paging: Pagination parameters in which to retrieve a page of dataindex: Current index of page of data to retrievesize: Number of rows of data per page to retrieve
sorting: List of parameters representing fields and direction in which to sort data from data repositoryparams: Sorting parameters in which to sort dataname: Name of field in which to sort datadirection: Sort direction of fieldASCsorts field in ascending orderDESCsorts field in descending order
{
"filters": {
"params": [
{
"name": "product_name",
"value": "iPhone",
"type": "CONTAINS",
"condition": "AND"
}
]
},
"paging": {
"index": 0,
"size": 2
},
"sorting": {
"params": [
{
"name": "product_name",
"direction": "ASC"
}
]
}
}Data contract containing data result. Includes page and record data.
Data in JSON format:
pageInfo: Object containing information about page dataindex: Current index of page of data retrievedsize: Number of rows of data in current page retrievedcount: Total number of pages in dataset
recordInfo: Object containing information about record datatotal: Total number of records in dataset
data: Array containing map of key/value pairs representing row(s) of data retrieved from data repository
{
"pageInfo": {
"index": 0,
"size": 2,
"count": 1
},
"recordInfo": {
"total": 2
},
"data": [
{
"product_id": "50d113a6-24ff-43cd-bb1d-ca3aa1014e4c",
"product_name": "Apple iPhone",
"product_sku": "123456",
"product_category": "mobile"
},
{
"product_id": "81bc7dde-5c9e-4736-baee-b82dc5f249e3",
"product_name": "Apple iPad",
"product_sku": "098765",
"product_category": "tablet"
}
]
}Several constant object values are provided:
| Object | Constant | Description | Data Type |
|---|---|---|---|
Dates |
SQL_MIN_DATE |
Provides a minimum SQL Date | java.sql.Date |
Several object formatters are provided:
| Object | Constant | Description | Data Type |
|---|---|---|---|
Formats |
SQL_DATE |
Formats a date to SQL date format | SimpleDateFormat |
Formats |
SQL_DATE_TIME |
Formats a date/time to SQL timestamp format | SimpleDateFormat |