You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Target GA release: same release as GA of Jakarta EE 11 in Open Liberty
Operating systems
Does the documentation apply to all operating systems?
Yes
No; specify operating systems: ______
Main page
Jakarta Data
Overview of Jakarta Data
Jakarta Data is a domain-driven model for relational and non-relational data access,
where you define simple Java objects to represent data and you define interfaces for operations on data.
You inject these interfaces into your application and use them to access data.
The implementation is supplied for you by a Jakarta Data Provider.
Concepts in Jakarta Data
Jakarta Data simplifies data access by allowing you to
represent data with simple Java objects (entities), and
define interfaces (repositories) with methods that perform operations on entities.
Jakarta Data Providers
Jakarta Data Providers supply an implementation of a repository, which can be injected into applications via CDI (Contexts and Dependency Injection).
Jakarta Data Providers can be third-party products or can be provided by the application server.
Open Liberty includes a built-in Jakarta Data Provider for relational database access
that is backed by the built-in Jakarta Persistence Provider, EclipseLink.
Some third-party Jakarta Data providers include Hibernate ORM (for relational data)and Eclipse JNoSQL (for various types of non-relational data).
Jakarta NoSQL entities for non-relational (NoSQL) data.
Jakarta Data Providers might define additional entity models, possibly by defining their own entity annotations,
or by defining conventions for supporting unannotated entities, or by some other vendor-specific model.
An entity can optionally have a static metamodel,
typically generated from the entity class by development tooling, which can be used by the repository interface
as well as the application in defining and invoking data access operations in a more type-safe manner.
By convention, static metamodel interface classes typically begin with the underscore (_) character, and is followed by the entity class name.
Repository interfaces must be annotated with the Repository
annotation and can optionally inherit from any of the following repository supertypes that are defined by Jakarta Data:
The repository supertypes offer a variety of pre-defined methods for commonly-used data access operations.
The first type parameter to the repository supertypes specifies a primary Entity class that can be assumed for repository methods that do not otherwise specify an Entity class.
The second type parameter to the repository supertypes specifies the type of the Id attribute that can be assumed for repository methods that do not otherwise specify an Id type.
Repository Interface Example
@RepositorypublicinterfaceCarsextendsBasicRepository<Car, String> {
@InsertCaradd(Carcar);
@OrderBy(_Car.ODOMETER)
@OrderBy(_Car.VIN)
List<Car> findByModelYearGreaterThanEqualAndPriceBetween(intminYear,
floatminPrice,
floatmaxPrice);
@FindPage<Car> search(@By(_Car.MAKE) Stringmanufacturer,
@By(_Car.MODEL) Stringmodel,
@By(_Car.MODELYEAR) intyear,
PageRequestpageRequest,
Order<Car> sortBy);
@Query("UPDATE Car SET price = ?2 WHERE vin = ?1")
booleansetPrice(StringvehicleIdNum, floatnewPrice);
@Query("SELECT price FROM Car WHERE vin = :vehicleId AND price > 0")
Optional<Float> getPrice(@Param("vehicleId") Stringvin);
@Deletebooleanremove(@By(ID) StringvehicleIdNum);
}
When there is only one Jakarta Data Provider that handles the type of entity, it is unnecessary for the Repository to specify which Jakarta Data Provider to use.
However, when multiple Jakarta Data providers coexist in a system and handle the same entity type,
the Repository must specify a provider name to disambiguate which Jakarta Data Provider is to be used.
Third-party Jakarta Data Providers can be used in Liberty by alternatively including the dataContainer-1.0 feature
which will only provide the Jakarta Data API (without the build-in Jakarta Data Provider).
Open Liberty includes a built-in Jakarta Data Provider for relational database access that is backed by the built-in Jakarta Persistence Provider, EclipseLink.
The built-in provider is available when you enable the data-1.0 feature
alongside the persistence-3.2 feature
or the jdbc-4.3 feature
or the jdbc-4.2 feature.
When multiple Jakarta Data providers supporting the Jakarta Persistence entities coexist in the system,
use the provider name of Liberty to explicitly request the built-in Jakarta Data Provider.
The built-in Jakarta Data Provider, which uses the built-in Jakarta Persistence Provider, EclipseLink, can connect to the same databases that EclipseLink supports.
Individual capabilities within Jakarta Data and the entity model are limited by the extent to which EcilpseLink supports each database.
The Default Database
If you do not specify otherwise, you end up with the Jakarta EE Default DataSource, which is java:comp/DefaultDataSource, as the data store for your repository.
The Jakarta EE Default DataSource is not configured by default in Liberty.
To configure it, include configuration of a <dataSource> with id of DefaultDataSource in your server configuration.
EclipseLink will attempt to create the necessary database tables automatically, which is convenient for development,
but is not efficient for running in production because checking for table existence incurs a lot of overhead and
database admin privileges might be required for table creation.
To specify which DataSource a repository will use, set the dataStore attribute of the @Repository annotation to one of:
JNDI name of a resource reference to a DataSource. For example, java:app/env/jdbc/MyDataSourceRef.
JNDI name of a DataSource. This could be from the name value of a @DataSourceDefinition or from the jndiName value of a dataSource from server configuration.
The id of a dataSource from server configuration.
When using JNDI names or resource reference names that are scoped to a namespace like java:comp or java:module,
you must ensure that the scope is accessible to the location of the repository interface within the application.
For example, a DataSource in the java:comp scope of an EJB is never accessible to a repository interface
because although a repository interface might exist in an EJB module, the repository interface is not part of any specific EJB.
A good practice when using scoped names is to use java:app to allow the repository interface to be defined in any module of the application.
EclipseLink will attempt to create the necessary database tables automatically, which is convenient for development,
but is not efficient for running in production because checking for table existence incurs a lot of overhead and database admin privileges might be required for table creation.
Defining a Persistence Unit gives you more control over the Jakarta Persistence configuration and EcilpseLink specific settings.
To specify which Persistence Unit a repository will use, set the dataStore attribute of the Repository annotation to a Persistence Unit reference.
The following sections provide an example of configuring and using a Persistence Unit reference.
The persistence unit reference can be defined in a Jakarta EE component. This example also defines a data source resource reference which is used by the persistence unit.
The persistence unit is defined according to the Jakarta Persistence specification.
It selects which DataSource to use and determines which entity classes are accessible to repositories.
Here is an example element in persistence.xml defining a persistence unit that is used by the prior examples,
The jakarta.persistence.schema-generation.database.action property, which is from the Jakarta Persistence specification,
allows you to request the automatic creation and/or removal of database tables.
Values for this setting include: create, drop, drop-and-create, none.
When using JNDI names or resource reference names that are scoped to a namespace like java:comp or java:module,
you must ensure that the scope is accessible to the location of the repository interface within the application.
For example, a Persistence Unit reference in the java:comp scope of an EJB is never accessible to a repository interface
because although a repository interface might exist in an EJB module, the repository interface is not part of any specific EJB.
A good practice when using scoped names is to use java:app to allow the repository interface to be defined in any module of the application.
Specifying a DatabaseStore
A databaseStore is an abstraction on top of a dataSource which gives you the ability to configure additional aspects related to Jakarta Persistence,
such as table creation and removal, without needing to provide persistence units.
Point the dataStore attribute of a Repository annotation at the id of a databaseStore element from server configuration.
The built-in Jakarta Data Provider allows Java records to be entities.
These entities are not annotated and instead rely on a couple of basic conventions to be interpreted as entities.
The built-in Jakarta Data Provider substitutes a Jakarta Persistence entity for the Java Record.
Thus the entity model for Java Record entities is in effect a subset of the Jakarta Persistence entity model,
with the difference that it is defined by a Java Record rather than entity annotations.
Record Components
The record components are the attributes of the entity.
Record components can be of any of the Basic Types that are specified by Jakarta Data.
These include types such as int, Integer, String, UUID, byte[], LocalDateTime, Instant, and enum types.
Some additional types for collections and embeddables can also be used.
Determining the Id
Precedence for determining the Id attribute (which is required), from highest to lowest:
record component name is "id", ignoring case.
record component name ends with "_id", ignoring case.
record component name ends with "Id" or "ID".
record component type is UUID with any name.
Use the same basic types for Ids that you can use with Jakarta Persistence entities.
You can also form composite Ids by using a type that is another Java record whose record components are basic types for Ids that you can use with Jakarta Persistence entities.
Determining the Version
Precedence for determining the version attribute (optional), from highest to lowest:
record component name is "version", ignoring case.
record component name is "_version", ignoring case.
Nullable Attributes
Record components with primitive types are non-nullable. Record component with other types are nullable.
Collection Attributes
Record component types that are instances of java.util.Collection are considered element collections.
Relation Attributes
Record components with other types (including Java record) are considered embeddables.
Like Java record entities, these embeddables are not annotated.
The static metamodel for a record entities is optional and follows the same rules and conventions as with other types of entities.
The static metamodel is typically generated by tooling.
A Repository that defines queries and other operations on Java Record entities must indicate its use of the Java Record as an entity in one of the following ways:
Inherit from a built-in repository superinterface and specify the Java Record class as its first type parameter.
Instead of inheriting from a built-in repository superinterface, define one or more life cycle methods (annotated with Insert, Delete, Save, or Update, all of which specify the same Java record type as the type of the parameter or as the element type of the collection or array that is the parameter.
Jakarta Persistence does not allow Java records to be entities. The built-in Jakarta Data provider makes this possible by substituting a generated Jakarta Persistence entity class for the record. The generated Jakarta Persistence entity class has a name that beings with the name of the record, followed by Entity. For example, if the Java record entity is named Product, a Jakarta Persistence entity named ProductEntity is generated and is used internally. The application must not define an entity of its own that collides with the generated name.
Java record entities offer a simple way to define entities at the expense of the richer programming model that is available to Jakarta Persistence entities. Where additional function is needed, use Jakarta Persistence entities instead.
Subpage of Built-in Jakarta Data Provider
Pagination and Page Requests
Jakarta Data offers two forms of pagination: Offset-based Pagination and Cursor-based Pagination. The built-in Jakarta Data provider supports both types.
Repository methods that perform pagination must accept a PageRequest parameter and return either Page or CursoredPage. Repository methods for cursor-based pagination must return a CursoredPage of the entity type. Repository methods for offset-based pagination must return a Page, which is typically of the entity type, but can alternatively be a Page of a record type where the record components are named to match a subset of the entity attributes, or can alternatively be a Page of a single entity attribute type. The latter requires annotating the repository method to have a Query annotation that supplies a JPQL query that selects a specific entity attribute of that type. Cursor-based pagination does not support returning cursored pages of anything other than the entity type because entity attribute values are used to construct the cursors relative to which next and previous pages are requested.
Sort Criteria for Pagination
For pagination to work correctly, sort criteria must define a consistent ordering of results. Sort criteria can be supplied to a repository method at run time via an Order, Sort, or Sort[] parameter. Sort criteria can be supplied by the repository during development time via the OrderBy annotation, the OrderBy Query by Method Name keyword, or the ORDER BY clause of a Query annotation value. Cursor-based pagination does not support the use of an ORDER BY clause in a Query annotation value. In additional, whe using cursor-based pagination, the Query annotation value must be written to end with a WHERE clause such that additional conditions can be appended by the Jakarta Data provider to fetch results relative to a cursor position.
Page Counts and Total Elements
The Jakarta Data API allows obtaining a total count of pages and elements across pages under certain conditions.
As indicated by the CursoredPage API, the total count of pages and count of total elements across pages are not accurate when using cursor-based pagination. Note that with cursor-based pagination, queries are performed relative to a cursor position and counts might not include elements prior to the cursor position. If total counts are needed with cursor-based pagination, write a separate countBy method or annotated Query method to retrieve the total count.
When using offset-pagination, the total count of pages and count of total elements can be accurately retrieved for pages that are retrieve via the Query by Method Name pattern, the Parameter-based Automatic Query pattern, and annotated Query methods that supply Jakarta Data Query Language (JDQL) queries that retrieve entities. Totals will also work with many Jakarta Persistence Query Language (JPQL) queries. Do not use pagination with queries that compute aggregate values such as COUNT(THIS) rather than retrieving entities.
Subpage of Built-in Jakarta Data Provider
Configuration of the built-in Jakarta Data Provider
This page describes the configuration options available for the built-in Jakarta Data Provider.
Logging parameters
By default, the built-in Jakarta Data Provider does not log the parameters passed to repository interface methods.
This default behavior ensures sensitive user data is not stored in cleartext in the logs, maintaining a secure operational environment.
However, to assist with debugging during development, developers can enable detailed logging for specific packages, repository interfaces, or individual repository methods.
Enabling Basic Trace Output
You can enable trace output for the data-1.0 feature by setting a trace specification in the logging element of your server.xml.
For example:
To aid in debugging, you can explicitly enable logging for specific packages, repository interfaces, or repository methods by using the logValues element under the data element.
This allows you to capture parameter values in the message and trace output for targeted debugging without exposing unnecessary information.
Consider when the getPrice method of the Cars repository interface:
@RepositorypublicinterfaceCarsextendsBasicRepository<Car, String> {
@Query("SELECT price FROM Car WHERE vin = :vehicleId")
Optional<Integer> getPrice(@Param("vehicleId") Stringvin);
}
You might see the following error message in messages.log:
[01/01/70, 00:00:00:000 UTC] 00000000 io.openliberty.data.internal.persistence.cdi.DataExtension E CWWKD1047E: The java.lang.Float result of the getPrice method of the io.openliberty.example.Cars repository interface cannot be converted to the Integer return type of the repository method because the result is not within the range of -2147483648 to 2147483647.
To see the value from the database that caused the error you can enable logValues for the specific method identified by the error:
This configuration produces a detailed error message with the failing value:
[01/01/70, 00:00:00:000 UTC] 00000000 io.openliberty.data.internal.persistence.cdi.DataExtension E CWWKD1047E: The java.lang.Float (3000000000.0) result of the getPrice method of the io.openliberty.example.Cars repository interface cannot be converted to the Integer return type of the repository method because the result is not within the range of -2147483648 to 2147483647.
Table management
The built-in Jakarta Data Provider includes configuration options to manage the lifecycle of database tables for entities associated with Jakarta Data repositories.
These options, defined by the createTables and dropTables attributes, allow you to control the behavior of table creation and removal.
Create Tables
The createTables configuration element determines whether the built-in Jakarta Data Provider should attempt to create database tables for repository entities when the repository's dataStore attribute points to a DataSource.
By default, the built-in Jakarta Data Provider will attempt to create tables.
The createTables configuration is ignored when the dataStore is a persistence unit reference, as table creation is governed by persistence unit properties.
Similarly, if the dataStore is a databaseStore id, table creation is determined by the databaseStore configuration.
Disabling createTables after tables are created can improve performance in production environments.
For situations where the database user does not have permission to create tables, the ddlGen tool
can be used to generate DDL scripts for the database administrator to execute.
The dropTables configuration element determines whether the built-in Jakarta Data Provider should attempt to remove database tables for repository entities when the repository's dataStore attribute points to a DataSource.
By default, the built-in Jakarta Data Provider will NOT attempt to remove tables.
The dropTables configuration is ignored when the dataStore is a persistence unit reference, as table removal is governed by persistence unit properties.
Similarly, if the dataStore is a databaseStore id, table removal is determined by the databaseStore configuration.
Enabling dropTables is useful for cleaning up test or development environments but should be used with caution in production to prevent accidental data loss.
This configuration provides a simple mechanism for managing database tables during development while protecting production environments from unintended changes.
Example configuration:
<server>
...
<datadropTables="false" />
</server>
Subpage of Built-in Jakarta Data Provider
Data Definition Language (DDL) Generation
Open Liberty includes a utility for generating Data Definition Language (DDL) scripts.
This utility, called ddlGen, simplifies the process of creating or replicating database schemas for applications running on Open Liberty servers.
Background
A databaseStore is a configuration element in Open Liberty that defines a persistence store used by server features, including Jakarta Data.
It specifies how and where data is stored and accessed, providing a central definition for database useage.
A persistence unit is defined by the Jakarta Persistence specification.
It represents a set of entity classes managed by EntityManager instances in an application.
These entity classes correspond to the data contained within a single data store.
A persistence unit is defined in a persistence.xml file and includes metadata about the entity classes, database connection details, and provider-specific configurations.
Overview of DDL Generation
The ddlGen utility is included with Open Liberty and is located in the wlp/bin/ directory as ddlGen (for Unix-like systems) and ddlGen.bat (for Windows).
It generates DDL files for databaseStore elements defined or generated in the server configuration, enabling database administrators to create or replicate schemas required by applications.
Detailed documentation about ddlGen is available in the Liberty DDL Generation Guide.
Considerations
If a repository interface is configured with a dataStore that points to a dataSource, such as:
The DefaultDataSource
A DataSource JNDI name
A DataSource resource reference
A DataSource configuration id (from server.xml)
Then, the ddlGen utility will be able to generate DDL files from a generated databaseStore.
This ensures the database schema required for Jakarta Data repositories are well-defined and easily manageable.
The ddlGen utility does not generate DDL files for repository interfaces configured with a dataStore that points to a persistence unit reference.
In these cases, DDL generation is handled by the Jakarta Persistence provider, which offers its own methods for creating schema definitions.
This ensures the separation of responsibilities and allows Jakarta Persistence to maintain full control over the management of its schema generation.
Purpose
The ddlGen utility generates DDL files for each databaseStore element defined or generated in the Open Liberty server configuration.
This includes all features that utilize the databaseStore element, including Jakarta Data.
For Jakarta Data, the generated DDL files are suffixed with _JakartaData.ddl.
The ddlGen utility enables database administrators to create or replicate schemas without granting schema-altering privileges (e.g., CREATE, DROP) to Open Liberty database users.
This approach ensures Liberty users can only perform operational tasks (e.g., INSERT, UPDATE, DELETE) while maintaining strict control over schema management.
Prerequisites
To use the ddlGen utility, the localConnector-1.0 feature must be enabled in the server configuration:
The generated DDL files will be stored in the wlp/usr/<server-name>/ddl/ directory.
Each file corresponds to a databaseStore defined or generated in the server configuration.
Example DDL files
The Choosing the Database section of the build-in Jakarta Data Provider documentation
has sample server configurations for each possible dataStore configuration possible on a repository interface.
This section has example DDL files for each of these examples to show how the output and file name can change in different situations.
CREATETABLECar (
VIN VARCHAR(255) FOR MIXED DATA NOT NULL,
MAKE VARCHAR(255) FOR MIXED DATA,
MODEL VARCHAR(255) FOR MIXED DATA,
MODELYEAR INTEGER,
ODOMETER INTEGER,
PRICE FLOAT,
PRIMARY KEY (VIN)
);
Feature epic details
Operating systems
Does the documentation apply to all operating systems?
Jakarta Data
Overview of Jakarta Data
Jakarta Data is a domain-driven model for relational and non-relational data access,
where you define simple Java objects to represent data and you define interfaces for operations on data.
You inject these interfaces into your application and use them to access data.
The implementation is supplied for you by a Jakarta Data Provider.
Concepts in Jakarta Data
Jakarta Data simplifies data access by allowing you to
Jakarta Data Providers
Jakarta Data Providers supply an implementation of a repository, which can be injected into applications via CDI (Contexts and Dependency Injection).
Jakarta Data Providers can be third-party products or can be provided by the application server.
Open Liberty includes a built-in Jakarta Data Provider for relational database access
that is backed by the built-in Jakarta Persistence Provider, EclipseLink.
Some third-party Jakarta Data providers include Hibernate ORM (for relational data)and
Eclipse JNoSQL (for various types of non-relational data).
Entity Model
Jakarta Data reuses the entity models of Jakarta Persistence
and Jakarta NoSQL.
Jakarta Data Providers might define additional entity models, possibly by defining their own entity annotations,
or by defining conventions for supporting unannotated entities, or by some other vendor-specific model.
Jakarta Persistence Entity Example
Static Metamodel
An entity can optionally have a static metamodel,
typically generated from the entity class by development tooling, which can be used by the repository interface
as well as the application in defining and invoking data access operations in a more type-safe manner.
By convention, static metamodel interface classes typically begin with the underscore (_) character, and is followed by the entity class name.
Static Metamodel Example
Repositories
Repository interfaces must be annotated with the Repository
annotation and can optionally inherit from any of the following repository supertypes that are defined by Jakarta Data:
The repository supertypes offer a variety of pre-defined methods for commonly-used data access operations.
The first type parameter to the repository supertypes specifies a primary Entity class that can be assumed for repository methods that do not otherwise specify an Entity class.
The second type parameter to the repository supertypes specifies the type of the Id attribute that can be assumed for repository methods that do not otherwise specify an Id type.
Repository Interface Example
Repository Interface Usage Example
Linking a Repository to a Provider
When there is only one Jakarta Data Provider that handles the type of entity, it is unnecessary for the Repository to specify which Jakarta Data Provider to use.
However, when multiple Jakarta Data providers coexist in a system and handle the same entity type,
the Repository must specify a provider name to disambiguate which Jakarta Data Provider is to be used.
The built-in Jakarta Data Provider for Liberty uses the provider name,
Liberty
.It is included in the data-1.0 feature
Third-party Jakarta Data Providers can be used in Liberty by alternatively including the
dataContainer-1.0 feature
which will only provide the Jakarta Data API (without the build-in Jakarta Data Provider).
Hibernate ORM Provider Name Example
Eclipse JNoSQL Provider Name Example
Built-in Provider Name Example
Built-in Jakarta Data Provider
Overview of Built-in Jakarta Data Provider
Open Liberty includes a built-in Jakarta Data Provider for relational database access that is backed by the built-in Jakarta Persistence Provider, EclipseLink.
The built-in provider is available when you enable the data-1.0 feature
alongside the persistence-3.2 feature
or the jdbc-4.3 feature
or the jdbc-4.2 feature.
Entity Model
The built-in provider accepts Jakarta Persistence entities or Java Records as entities.
Provider Name
When multiple Jakarta Data providers supporting the Jakarta Persistence entities coexist in the system,
use the provider name of
Liberty
to explicitly request the built-in Jakarta Data Provider.Choosing the Database
The built-in Jakarta Data Provider, which uses the built-in Jakarta Persistence Provider, EclipseLink, can connect to the same databases that EclipseLink supports.
Individual capabilities within Jakarta Data and the entity model are limited by the extent to which EcilpseLink supports each database.
The Default Database
If you do not specify otherwise, you end up with the Jakarta EE Default DataSource, which is
java:comp/DefaultDataSource
, as the data store for your repository.The Jakarta EE Default DataSource is not configured by default in Liberty.
To configure it, include configuration of a
<dataSource>
with id ofDefaultDataSource
in your server configuration.Repository interface:
Server configuration:
EclipseLink will attempt to create the necessary database tables automatically, which is convenient for development,
but is not efficient for running in production because checking for table existence incurs a lot of overhead and
database admin privileges might be required for table creation.
Refer to the sections on Specifying a DatabaseStore and Specifying a Persistence Unit Reference
for information about how to control the table creation settings.
Specifying a DataSource
To specify which DataSource a repository will use, set the
dataStore
attribute of the@Repository
annotation to one of:java:app/env/jdbc/MyDataSourceRef
.name
value of a@DataSourceDefinition
or from thejndiName
value of adataSource
from server configuration.id
of adataSource
from server configuration.When using JNDI names or resource reference names that are scoped to a namespace like
java:comp
orjava:module
,you must ensure that the scope is accessible to the location of the repository interface within the application.
For example, a DataSource in the
java:comp
scope of an EJB is never accessible to a repository interfacebecause although a repository interface might exist in an EJB module, the repository interface is not part of any specific EJB.
A good practice when using scoped names is to use
java:app
to allow the repository interface to be defined in any module of the application.EclipseLink will attempt to create the necessary database tables automatically, which is convenient for development,
but is not efficient for running in production because checking for table existence incurs a lot of overhead and database admin privileges might be required for table creation.
Refer to the sections on Specifying a DatabaseStore and Specifying a Persistence Unit Reference
for information about how to control the table creation settings.
DataSource id Example
This example shows a repository interface that points to the
id
of a<dataSource>
in server configuration.Repository interface:
Server configuration:
DataSource jndiName Example
This example shows a repository interface that points to the
jndiName
of a<dataSource>
in server configuration.Repository interface:
Server configuration:
DataSource Resource Reference Example
This example shows a repository interface that points to a resource reference to a
<dataSource>
in server configuration.Repository interface:
Jakarta EE component (defines the resource reference):
Server configuration:
DataSourceDefinition Example
This example shows a repository interface that points to the
name
of aDataSourceDefinition
.Repository interface:
Web component or EJB component (defines the DataSourceDefinition):
Specifying a Persistence Unit Reference
Defining a Persistence Unit gives you more control over the Jakarta Persistence configuration and EcilpseLink specific settings.
To specify which Persistence Unit a repository will use, set the dataStore attribute of the Repository annotation to a Persistence Unit reference.
The following sections provide an example of configuring and using a Persistence Unit reference.
Repository interface
Jakarta EE component
The persistence unit reference can be defined in a Jakarta EE component. This example also defines a data source resource reference which is used by the persistence unit.
Persistence Unit
The persistence unit is defined according to the Jakarta Persistence specification.
It selects which DataSource to use and determines which entity classes are accessible to repositories.
Here is an example element in persistence.xml defining a persistence unit that is used by the prior examples,
The
jakarta.persistence.schema-generation.database.action
property, which is from the Jakarta Persistence specification,allows you to request the automatic creation and/or removal of database tables.
Values for this setting include:
create
,drop
,drop-and-create
,none
.DataSource in server configuration:
When using JNDI names or resource reference names that are scoped to a namespace like
java:comp
orjava:module
,you must ensure that the scope is accessible to the location of the repository interface within the application.
For example, a Persistence Unit reference in the
java:comp
scope of an EJB is never accessible to a repository interfacebecause although a repository interface might exist in an EJB module, the repository interface is not part of any specific EJB.
A good practice when using scoped names is to use
java:app
to allow the repository interface to be defined in any module of the application.Specifying a DatabaseStore
A
databaseStore
is an abstraction on top of adataSource
which gives you the ability to configure additional aspects related to Jakarta Persistence,such as table creation and removal, without needing to provide persistence units.
Point the
dataStore
attribute of aRepository
annotation at theid
of adatabaseStore
element from server configuration.Repository interface:
Server configuration:
Java Records as Entities
The built-in Jakarta Data Provider allows Java records to be entities.
These entities are not annotated and instead rely on a couple of basic conventions to be interpreted as entities.
The built-in Jakarta Data Provider substitutes a Jakarta Persistence entity for the Java Record.
Thus the entity model for Java Record entities is in effect a subset of the Jakarta Persistence entity model,
with the difference that it is defined by a Java Record rather than entity annotations.
Record Components
The record components are the attributes of the entity.
Record components can be of any of the Basic Types that are specified by Jakarta Data.
These include types such as
int
,Integer
,String
,UUID
,byte[]
,LocalDateTime
,Instant
, and enum types.Some additional types for collections and embeddables can also be used.
Determining the Id
Precedence for determining the Id attribute (which is required), from highest to lowest:
Use the same basic types for Ids that you can use with Jakarta Persistence entities.
You can also form composite Ids by using a type that is another Java record whose record components are basic types for Ids that you can use with Jakarta Persistence entities.
Determining the Version
Precedence for determining the version attribute (optional), from highest to lowest:
Nullable Attributes
Record components with primitive types are non-nullable. Record component with other types are nullable.
Collection Attributes
Record component types that are instances of
java.util.Collection
are considered element collections.Relation Attributes
Record components with other types (including Java record) are considered embeddables.
Like Java record entities, these embeddables are not annotated.
Record Entity Example
The static metamodel for a record entities is optional and follows the same rules and conventions as with other types of entities.
The static metamodel is typically generated by tooling.
Static Metamodel Example
Identifying When a Record is an Entity
A Repository that defines queries and other operations on Java Record entities must indicate its use of the Java Record as an entity in one of the following ways:
Inherit from a built-in repository superinterface and specify the Java Record class as its first type parameter.
Repository with Superinterface Example
Instead of inheriting from a built-in repository superinterface, define one or more life cycle methods (annotated with
Insert
,Delete
,Save
, orUpdate
, all of which specify the same Java record type as the type of the parameter or as the element type of the collection or array that is the parameter.Repository with Life Cycle Methods Example
Example Table for a Record Entity
...
Limitations of Record Entities
Jakarta Persistence does not allow Java records to be entities. The built-in Jakarta Data provider makes this possible by substituting a generated Jakarta Persistence entity class for the record. The generated Jakarta Persistence entity class has a name that beings with the name of the record, followed by
Entity
. For example, if the Java record entity is namedProduct
, a Jakarta Persistence entity namedProductEntity
is generated and is used internally. The application must not define an entity of its own that collides with the generated name.Java record entities offer a simple way to define entities at the expense of the richer programming model that is available to Jakarta Persistence entities. Where additional function is needed, use Jakarta Persistence entities instead.
Pagination and Page Requests
Jakarta Data offers two forms of pagination: Offset-based Pagination and Cursor-based Pagination. The built-in Jakarta Data provider supports both types.
Repository methods that perform pagination must accept a
PageRequest
parameter and return eitherPage
orCursoredPage
. Repository methods for cursor-based pagination must return aCursoredPage
of the entity type. Repository methods for offset-based pagination must return aPage
, which is typically of the entity type, but can alternatively be aPage
of a record type where the record components are named to match a subset of the entity attributes, or can alternatively be aPage
of a single entity attribute type. The latter requires annotating the repository method to have aQuery
annotation that supplies a JPQL query that selects a specific entity attribute of that type. Cursor-based pagination does not support returning cursored pages of anything other than the entity type because entity attribute values are used to construct the cursors relative to which next and previous pages are requested.Sort Criteria for Pagination
For pagination to work correctly, sort criteria must define a consistent ordering of results. Sort criteria can be supplied to a repository method at run time via an
Order
,Sort
, orSort[]
parameter. Sort criteria can be supplied by the repository during development time via theOrderBy
annotation, theOrderBy
Query by Method Name keyword, or theORDER BY
clause of aQuery
annotation value. Cursor-based pagination does not support the use of anORDER BY
clause in aQuery
annotation value. In additional, whe using cursor-based pagination, theQuery
annotation value must be written to end with aWHERE
clause such that additional conditions can be appended by the Jakarta Data provider to fetch results relative to a cursor position.Page Counts and Total Elements
The Jakarta Data API allows obtaining a total count of pages and elements across pages under certain conditions.
As indicated by the
CursoredPage
API, the total count of pages and count of total elements across pages are not accurate when using cursor-based pagination. Note that with cursor-based pagination, queries are performed relative to a cursor position and counts might not include elements prior to the cursor position. If total counts are needed with cursor-based pagination, write a separatecountBy
method or annotatedQuery
method to retrieve the total count.When using offset-pagination, the total count of pages and count of total elements can be accurately retrieved for pages that are retrieve via the Query by Method Name pattern, the Parameter-based Automatic Query pattern, and annotated
Query
methods that supply Jakarta Data Query Language (JDQL) queries that retrieve entities. Totals will also work with many Jakarta Persistence Query Language (JPQL) queries. Do not use pagination with queries that compute aggregate values such asCOUNT(THIS)
rather than retrieving entities.Configuration of the built-in Jakarta Data Provider
The built-in Jakarta Data Provider is configured using the
data
element in server.xmlwhen using the data-1.0 feature is enabled.
This page describes the configuration options available for the built-in Jakarta Data Provider.
Logging parameters
By default, the built-in Jakarta Data Provider does not log the parameters passed to repository interface methods.
This default behavior ensures sensitive user data is not stored in cleartext in the logs, maintaining a secure operational environment.
However, to assist with debugging during development, developers can enable detailed logging for specific packages, repository interfaces, or individual repository methods.
Enabling Basic Trace Output
You can enable trace output for the
data-1.0
feature by setting a trace specification in the logging element of your server.xml.For example:
Customizing Trace Output for Debugging
To aid in debugging, you can explicitly enable logging for specific packages, repository interfaces, or repository methods by using the
logValues
element under thedata
element.This allows you to capture parameter values in the message and trace output for targeted debugging without exposing unnecessary information.
Consider when the
getPrice
method of theCars
repository interface:is invoked from an application resource:
You might see the following error message in messages.log:
To see the value from the database that caused the error you can enable
logValues
for the specific method identified by the error:This configuration produces a detailed error message with the failing value:
Table management
The built-in Jakarta Data Provider includes configuration options to manage the lifecycle of database tables for entities associated with Jakarta Data repositories.
These options, defined by the
createTables
anddropTables
attributes, allow you to control the behavior of table creation and removal.Create Tables
The
createTables
configuration element determines whether the built-in Jakarta Data Provider should attempt to create database tables for repository entities when the repository'sdataStore
attribute points to a DataSource.By default, the built-in Jakarta Data Provider will attempt to create tables.
The
createTables
configuration is ignored when thedataStore
is a persistence unit reference, as table creation is governed by persistence unit properties.Similarly, if the
dataStore
is adatabaseStore
id, table creation is determined by thedatabaseStore
configuration.Disabling
createTables
after tables are created can improve performance in production environments.For situations where the database user does not have permission to create tables, the ddlGen tool
can be used to generate DDL scripts for the database administrator to execute.
Example configuration:
Drop Tables
The
dropTables
configuration element determines whether the built-in Jakarta Data Provider should attempt to remove database tables for repository entities when the repository'sdataStore
attribute points to a DataSource.By default, the built-in Jakarta Data Provider will NOT attempt to remove tables.
The
dropTables
configuration is ignored when thedataStore
is a persistence unit reference, as table removal is governed by persistence unit properties.Similarly, if the
dataStore
is adatabaseStore
id, table removal is determined by thedatabaseStore
configuration.Enabling
dropTables
is useful for cleaning up test or development environments but should be used with caution in production to prevent accidental data loss.This configuration provides a simple mechanism for managing database tables during development while protecting production environments from unintended changes.
Example configuration:
Data Definition Language (DDL) Generation
Open Liberty includes a utility for generating Data Definition Language (DDL) scripts.
This utility, called
ddlGen
, simplifies the process of creating or replicating database schemas for applications running on Open Liberty servers.Background
A
databaseStore
is a configuration element in Open Liberty that defines a persistence store used by server features, including Jakarta Data.It specifies how and where data is stored and accessed, providing a central definition for database useage.
A
persistence unit
is defined by the Jakarta Persistence specification.It represents a set of entity classes managed by EntityManager instances in an application.
These entity classes correspond to the data contained within a single data store.
A persistence unit is defined in a
persistence.xml
file and includes metadata about the entity classes, database connection details, and provider-specific configurations.Overview of DDL Generation
The
ddlGen
utility is included with Open Liberty and is located in thewlp/bin/
directory asddlGen
(for Unix-like systems) andddlGen.bat
(for Windows).It generates DDL files for
databaseStore
elements defined or generated in the server configuration, enabling database administrators to create or replicate schemas required by applications.Detailed documentation about ddlGen is available in the Liberty DDL Generation Guide.
Considerations
If a repository interface is configured with a
dataStore
that points to adataSource
, such as:Then, the ddlGen utility will be able to generate DDL files from a
generated databaseStore
.This ensures the database schema required for Jakarta Data repositories are well-defined and easily manageable.
The ddlGen utility does not generate DDL files for repository interfaces configured with a
dataStore
that points to a persistence unit reference.In these cases, DDL generation is handled by the Jakarta Persistence provider, which offers its own methods for creating schema definitions.
This ensures the separation of responsibilities and allows Jakarta Persistence to maintain full control over the management of its schema generation.
Purpose
The ddlGen utility generates DDL files for each
databaseStore
element defined or generated in the Open Liberty server configuration.This includes all features that utilize the
databaseStore
element, including Jakarta Data.For Jakarta Data, the generated DDL files are suffixed with
_JakartaData.ddl
.The ddlGen utility enables database administrators to create or replicate schemas without granting schema-altering privileges (e.g., CREATE, DROP) to Open Liberty database users.
This approach ensures Liberty users can only perform operational tasks (e.g., INSERT, UPDATE, DELETE) while maintaining strict control over schema management.
Prerequisites
To use the ddlGen utility, the
localConnector-1.0
feature must be enabled in the server configuration:Running the ddlGen Utility
The generated DDL files will be stored in the
wlp/usr/<server-name>/ddl/
directory.Each file corresponds to a
databaseStore
defined or generated in the server configuration.Example DDL files
The Choosing the Database section of the build-in Jakarta Data Provider documentation
has sample server configurations for each possible
dataStore
configuration possible on a repository interface.This section has example DDL files for each of these examples to show how the output and file name can change in different situations.
Default DataSource
DDL file name:
...databaseStore\[java.comp.DefaultDataSource\]\_JakartaData.ddl
DDL file output:
DataSource Id
DDL file name:
...databaseStore\[ExampleDataSourceID\]\_JakartaData.ddl
DDL file output:
DataSource JNDI Name
DDL file name:
...databaseStore\[jdbc.ExampleDataSource\]\_JakartaData.ddl
DDL file output:
DataSource Resource Reference
DDL file name:
...databaseStore\[java.app.env.jdbc.ExampleDataSourceRef\]\_JakartaData.ddl
DDL file output:
DataSource Definition
DDL file name:
...databaseStore\[java.comp.jdbc.ExampleDataSourceDef\]\_JakartaData.ddl
DDL file output:
Persistence Unit Reference
No DDL file created, DDL generation is handled by the Jakarta Persistence provider, which offers its own methods for creating schema definitions.
DatabaseStore
DDL file name:
...databaseStore\[ExampleDatabaseStore\]\_JakartaData.ddl
DDL file output:
The text was updated successfully, but these errors were encountered: