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.sql
To create database, run:
psql postgres -f migrations/create_database.sql
To deploy database schema, copy gradle-default.properties
from
Vault to project root and run:
./gradlew flywayMigrate -PenvironmentName=default
When 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:
delete
deleteByIds
exists
get
save
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
}
}
name
is the name of the data providerid
is the name of the entity class@Id
fieldmappings
provides the mappings from the consumer model to the entity class via aMap<String, Any>
key
is the consumer model field namevalue
is the entity class field name
idConverter
provides a function to convert an identifier value to an entity class@Id
field data typefilterMapper
provides the filters available used to filter dataobjectFieldMapper
constructs an entity class from a row of datarowColumnMapper
constructs 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 fieldEQUALS
performs equality filter on fieldCONTAINS
performs contains filter on field
condition
: Filter condition for fieldAND
creates an and condition for fieldOR
creates 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 fieldASC
sorts field in ascending orderDESC
sorts 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 |