Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRAFT IN PROGRESS - DO NOT START ON THIS YET - Documentation, Jakarta Data 1.0 #7468

Open
1 of 2 tasks
njr-11 opened this issue Aug 14, 2024 · 0 comments
Open
1 of 2 tasks
Assignees

Comments

@njr-11
Copy link

njr-11 commented Aug 14, 2024

--- STILL IN PROGRESS BY DEV TEAM. DO NOT START ON DOCUMENTATION FOR THIS YET ---

Feature epic details

Operating systems

Does the documentation apply to all operating systems?

  • Yes
  • No; specify operating systems: ______

Jakarta Data

Overview of Jakarta Data

Jakarta Data is a programming 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 it.

Jakarta Data Providers

Jakarta Data Providers supply the implementation of repositories, 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 (link) 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 Persistence entities for 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.

Jakarta Persistence Entity Example

@Entity
public class Car {
    @Id
    public String vin; 

    public String make;

    public String model;

    public int modelYear;

    public int odometer;

    public float price;
}

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, which is followed by the entity class name.

Static Metamodel Example

@StaticMetamodel(Car.class)
public interface _Car {
    String MAKE = "make";
    String MODEL = "model";
    String MODELYEAR = "modelYear";
    String ODOMETER = "odometer";
    String PRICE = "price";
    String VIN = "vin";

    TextAttribute<Car> make = new TextAttributeRecord<>(MAKE);
    TextAttribute<Car> model = new TextAttributeRecord<>(MODEL);
    SortableAttribute<Car> modelYear = new SortableAttributeRecord<>(MODELYEAR);
    SortableAttribute<Car> odometer = new SortableAttributeRecord<>(ODOMETER);
    SortableAttribute<Car> price = new SortableAttributeRecord<>(PRICE);
    TextAttribute<Car> vin = new TextAttributeRecord<>(VIN);
}

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 field that can be assumed for repository methods that do not otherwise specify an Id type.

Repository Interface Example

@Repository
public interface Cars extends BasicRepository<Car, String> {
    @Insert
    Car add(Car car);

    @OrderBy(_Car.ODOMETER)
    @OrderBy(_Car.VIN)
    List<Car> findByModelYearGreaterThanEqualAndPriceBetween(int minYear,
                                                             float minPrice,
                                                             float maxPrice);

    @Find
    Page<Car> search(@By(_Car.MAKE) String manufacturer,
                     @By(_Car.MODEL) String model,
                     @By(_Car.MODELYEAR) int year,
                     PageRequest pageRequest,
                     Order<Car> sortBy);

    @Query("UPDATE Car SET price = ?2 WHERE vin = ?1")
    boolean setPrice(String vehicleIdNum, float newPrice);

    @Query("SELECT price FROM Car WHERE vin = :vehicleId AND price > 0")
    Optional<Float> getPrice(@Param("vehicleId") String vin);

    @Delete
    boolean remove(@By(ID) String vehicleIdNum);
}

Repository Interface Usage Example

@Path("/cars")
@ApplicationScoped
public class ExampleResource {
    @Inject
    Cars cars;

    @GET
    @Path("/make/{make}/model/{model}/year/{year}/page/{pageNum}")
    @Produces(MediaType.TEXT_PLAIN)
    public String search(
            @PathParam("make") String make,
            @PathParam("model") String model,
            @PathParam("year") int year,
            @PathParam("pageNum") long pageNum) {

        PageRequest pageRequest = PageRequest.ofPage(pageNum).size(10);

        Order<Car> mostToLeastExpensive = Order.by(
                _Car.price.desc(),
                _Car.vin.asc());

        Page<Car> page = cars.search(make, model, year, 
                                     pageRequest, 
                                     mostToLeastExpensive);

        return page.stream()
                .map(c -> c.modelYear + " " + c.make + " " + c.model + " " +
                          c.odometer + " miles $" + c.price + " #" + c.vin)
                .collect(Collectors.toList())
                .toString();
    }
}

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 used.

The built-in Jakarta Data Provider uses the provider name, "Liberty".
It is included in the data-1.0 feature (link) and can be made unavailable (so it does not conflict with a third-party Jakarta Data Provider) by configuring the Liberty server to instead use the dataContainer-1.0 feature (link).

Hibernate ORM Provider Name Example

@Repository(provider = "Hibernate", dataStore = "MyPersistenceUnit")
public interface Employee extends CrudRepository<Employee, Long> {
}

Eclipse JNoSQL Provider Name Example

@Repository(provider = "Eclipse JNoSQL") //TODO update https://github.com/eclipse/jnosql/pull/559
public interface Cars extends BasicRepository<Car, String> {
}

Built-in Provider Name Example

@Repository(provider = "Liberty", dataStore = "java:app/env/jdbc/MyDataSourceRef")
public interface Products extends CrudRepository<Product, String> {
}

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 (link) alongside the persistence-3.2 feature (link) or jdbc-4.3 feature or jdbc-4.2 feature (links).

Entity Model

The built-in provider accepts Jakarta Persistence entities or Java Records as entities (link).

Provider Name

When multiple Jakarta Data providers supporting the same types of entities coexist in the system, use the provider name of "Liberty" to explicitly request the built-in Jakarta Data Provider.

@Repository(provider = "Liberty")
public interface Products extends BasicRepository<Product, String> {
}

DDL Generation

The ddlGen binary is provided by Liberty and is found alongside the Liberty installation in wlp/bin/ddlGen and wlp/bin/ddlGen.bat.
More detailed documentation on the ddlGen binary can be found at https://www.ibm.com/docs/en/was-liberty/nd?topic=line-generating-data-definition-language

Usage

The ddlGen binary will create a data definition language (DDL) file for each databaseStore element present on a Liberty server at runtime.
This includes all features on Liberty that utiltize the databaseStore configuration element.
The DDL files generated for Jakarta Data databaseStore elements will be suffixed with _JakartaData.ddl.

This utility will allow database administrators the ability to create or replicate the database schema necessary for the application(s) installed on a
Liberty server using their administrative priviages.
While at the same time limiting the privlages given to Liberty database user(s) to create connections, insert, update, and delete data from tables.

Server Configuration

To use the ddlGen binary you must enable the localConnector-1.0 feature on your server:

<featureManager>
  <feature>localConnector-1.0</feature>
</featureManager>

Execute

To execute the ddlGen binary first start your sever:

$ ./bin/server start <server-name>
$ ./bin/ddlGen generate <server-name>
$ ./bin/server stop <server-name>

After successful execution of the ddlGen binary, a new directory will be created under wlp/usr/<server-name>/ddl/
and will contain a set of DDL files for each databaseStore.

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 of DefaultDataSource in your server configuration.

Repository interface:

@Repository //Default dataStore = "java:comp/DefaultDataSource"
public interface Cars extends BasicRepository<Cars, String> {
  // Query methods
}

Server configuration:

<dataSource id="DefaultDataSource">
  <jdbcDriver libraryRef="PostgresLib"/>
  <properties.postgresql databaseName="exampledb" serverName="localhost" portNumber="5432"/>
  <containerAuthData user="dbuser1" password="dbpwd1"/>
</dataSource>

<library id="PostgresLib">
  <fileset dir="${server.config.dir}/lib/postgres" includes="*.jar"/>
</library>

Expected DDL File ( ...databaseStore[java.comp.DefaultDataSource]_JakartaData.ddl ):

CREATE TABLE Car (
	VIN VARCHAR(255) NOT NULL, MAKE VARCHAR(255), MODEL VARCHAR(255),
	MODELYEAR INTEGER, ODOMETER INTEGER, PRICE FLOAT,
	PRIMARY KEY (VIN)
);

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 [link] and Specifying a Persistence Unit Reference [link] 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:

  • 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.
Refer to the sections on Specifying a DatabaseStore [link] and Specifying a Persistence Unit Reference [link] 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:

@Repository(dataStore = "ExampleDataSourceID")
public interface Cars extends BasicRepository<Cars, String> {
    // Query methods
}

Server configuration:

<dataSource id="ExampleDataSourceID">
  <jdbcDriver libraryRef="OracleLib"/>
  <properties.oracle URL="jdbc:oracle:thin:@localhost:1521:exampledb"/>
  <containerAuthData user="dbuser1" password="dbpwd1"/>
</dataSource>

<library id="OracleLib">
  <fileset dir="${server.config.dir}/lib/ojdbc" includes="*.jar"/>
</library>

Expected DDL File ( ...databaseStore[ExampleDataSourceID]_JakartaData.ddl ):

CREATE TABLE Car (
    VIN NVARCHAR2(255) NOT NULL, MAKE NVARCHAR2(255) NULL, MODEL NVARCHAR2(255) NULL,
    MODELYEAR NUMBER(10) NULL, ODOMETER NUMBER(10) NULL, PRICE NUMBER(19,4) NULL,
    PRIMARY KEY (VIN)
)

EXIT;

DataSource jndiName Example

This example shows a repository interface that points to the jndiName of a <dataSource> in server configuration.

Repository interface:

@Repository(dataStore = "jdbc/ExampleDataSource")
public interface Cars extends BasicRepository<Car, String> {
    // Query methods
}

Server configuration:

<dataSource jndiName="jdbc/ExampleDataSource">
  <jdbcDriver libraryRef="DB2Lib"/>
  <properties.db2.jcc databaseName="exampledb" serverName="localhost" portNumber="50000"/>
  <containerAuthData user="dbuser1" password="dbpwd1"/>
</dataSource>

<library id="DB2Lib">
  <fileset dir="${server.config.dir}/lib/jcc" includes="*.jar"/>
</library>

Expected DDL File ( ...databaseStore[jdbc.ExampleDataSource]_JakartaData.ddl ):

CREATE TABLE Car (
    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)
);

DataSource Resource Reference Example

This example shows a repository interface that points to a resource reference to a <dataSource> in server configuration.

Repository interface:

@Repository(dataStore = "java:app/env/jdbc/ExampleDataSourceRef")
public interface Cars extends BasicRepository<Car, String> {
    // Query methods
}

Jakarta EE component (defines the resource reference):

@ApplicationScoped
@Path("/cars")
public class ExampleResource {
    @Resource(name = "java:app/env/jdbc/ExampleDataSourceRef",
              lookup = "jdbc/ExampleDataSource")
    DataSource ds;

    @Inject
    Cars cars;

    // ...
}

Server configuration:

<dataSource jndiName="jdbc/ExampleDataSource">
  <jdbcDriver libraryRef="SQLServerLib"/>
  <properties.microsoft.sqlserver databaseName="exampledb" serverName="localhost" portNumber="1433"/>
  <containerAuthData user="dbuser1" password="dbpwd1"/>
</dataSource>

<library id="SQLServerLib">
  <fileset dir="${server.config.dir}/lib/sqlserver" includes="*.jar"/>
</library>

Expected DDL File ( ...databaseStore[java.app.env.jdbc.ExampleDataSourceRef]_JakartaData.ddl ):

CREATE TABLE Car (
    VIN NVARCHAR(255) NOT NULL, MAKE NVARCHAR(255) NULL, MODEL NVARCHAR(255) NULL,
    MODELYEAR INTEGER NULL, ODOMETER INTEGER NULL, PRICE FLOAT(16) NULL,
    PRIMARY KEY (VIN)
);

DataSourceDefinition Example

This example shows a repository interface that points to the name of a DataSourceDefinition.

Repository interface:

@Repository(dataStore = "java:comp/jdbc/ExampleDataSourceDef")
public interface Cars extends BasicRepository<Car, String> {
    // Query methods
}

Web component or EJB component (defines the DataSourceDefinition):

@ApplicationScoped
@DataSourceDefinition(name = "java:comp/jdbc/ExampleDataSourceDef",
                      className = "org.apache.derby.jdbc.EmbeddedXADataSource",
                      databaseName = "memory:exampledb",
                      user = "dbuser1",
                      password = "dbpwd1",
                      properties = "createDatabase=create")
@Path("/cars")
public class ExampleResource {
    @Inject
    Cars cars;

    // ...
}

Expected DDL File ( ...databaseStore[java.comp.jdbc.ExampleDataSourceDef]_JakartaData.ddl ):

CREATE TABLE Car (
    VIN VARCHAR(255) NOT NULL, MAKE VARCHAR(255), MODEL VARCHAR(255),
    MODELYEAR INTEGER, ODOMETER INTEGER, PRICE FLOAT,
    PRIMARY KEY (VIN)
)

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 secions provide an example of configuring and using a Persistence Unit reference.

Repository interface

@Repository(dataStore = "java:app/env/persistence/ExamplePersistenceUnitRef")
public interface Cars extends BasicRepository<Car, String> {
    // Query methods
}

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.

@ApplicationScoped
@Path("/cars")
public class ExampleResource {
    @PersistenceUnit(name = "java:app/env/persistence/ExamplePersistenceUnitRef",
                     unitName = "ExamplePersistenceUnit")
    EntityManagerFactory emf;

    @Resource(name = "java:app/env/jdbc/ExampleDataSourceRef",
              lookup = "jdbc/ExampleDataSource")
    DataSource ds;

    @Inject
    Cars cars;

    // ...
}

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 entry in persistence.xml defining a persistence unit that is used by the prior examples,

<persistence-unit name="ExamplePersistenceUnit">
  <jta-data-source>java:app/env/jdbc/ExampleDataSourceRef</jta-data-source>
  <class>example.data.entity.Car</class>
  <properties>
    <property name="jakarta.persistence.schema-generation.database.action" value="create"/>
    <property name="eclipselink.logging.parameters" value="true"/>
  </properties>
</persistence-unit>

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:

<dataSource jndiName="jdbc/ExampleDataSource">
  <jdbcDriver libraryRef="PostgresLib"/>
  <properties.postgresql databaseName="exampledb" serverName="localhost" portNumber="5432"/>
  <containerAuthData user="dbuser1" password="dbpwd1"/>
</dataSource>

<library id="PostgresLib">
  <fileset dir="${server.config.dir}/lib/postgres" includes="*.jar"/>
</library>

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.

Expected DDL File

File name: ...databaseStore[java.app.env.persistence.ExamplePersistenceUnitRef]_JakartaData.ddl

Content:

CREATE TABLE Car (
    VIN VARCHAR(255) NOT NULL, MAKE VARCHAR(255), MODEL VARCHAR(255),
    MODELYEAR INTEGER, ODOMETER INTEGER, PRICE FLOAT,
    PRIMARY KEY (VIN)
);

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.
It also ties into to the ddlgen tool, which generates DDL files for a database admin to run manually under the required database privileges.

Point the dataStore attribute of a Repository annotation at the id of a databaseStore element from server configuration.

Repository interface:

@Repository(dataStore = "ExampleDatabaseStore")
public interface Cars extends BasicRepository<Car, String> {
    // Query methods
}

Server configuration:

<databaseStore id="ExampleDatabaseStore"
               dataSourceRef="ExampleDataSource"
               createTables="false"
               schema="JAKARTA"
               tablePrefix="DATA">
  <authData user="dbuser1" password="dbpwd1"/>
</databaseStore>

<dataSource id="ExampleDataSource">
  <jdbcDriver libraryRef="PostgresLib"/>
  <properties.postgresql databaseName="exampledb" serverName="localhost" portNumber="5432"/>
</dataSource>

<library id="PostgresLib">
  <fileset dir="${server.config.dir}/lib/postgres" includes="*.jar"/>
</library>

Expected DDL File

File name: ...databaseStore[ExampleDatabaseStore]_JakartaData.ddl

Content:

CREATE TABLE JAKARTA.DATACar (
    VIN VARCHAR(255) NOT NULL, MAKE VARCHAR(255), MODEL VARCHAR(255),
    MODELYEAR INTEGER, ODOMETER INTEGER, PRICE FLOAT,
    PRIMARY KEY (VIN)
);

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 or fields of the entity.

Persistent Field Types (basic types) that are specified by Jakarta Data can be used.
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.

Record Entity Example

public record Rectangle(
                String id,
                Point position,
                int height,
                int width,
                long version) {
 
    public static record Point(
                    int x,
                    int y) {
    }
}

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

@StaticMetamodel(Rectangle.class)
public interface _Rectangle {
    String HEIGHT = "height";
    String ID = "id";
    String POSITION = "position";
    String POSITION_X = "position.x";
    String POSITION_Y = "position.y";
    String VERSION = "version";
    String WIDTH = "width";

    SortableAttribute<Rectangle> height = new SortableAttributeRecord<>(HEIGHT);
    TextAttribute<Rectangle> id = new TextAttributeRecord<>(ID);
    Attribute<Rectangle> position = new AttributeRecord<>(POSITION);
    SortableAttribute<Rectangle> position_x = new SortableAttributeRecord<>(POSITION_X);
    SortableAttribute<Rectangle> position_y = new SortableAttributeRecord<>(POSITION_Y);
    SortableAttribute<Rectangle> version = new SortableAttributeRecord<>(VERSION);
    SortableAttribute<Rectangle> width = new SortableAttributeRecord<>(WIDTH);
}

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:

  1. Inherit from a built-in repository superinterface and specify the Java Record class as its first type parameter.

    Repository with Superinterface Example

    @Repository
    public interface Rectangles extends CrudRepository<Rectangle, String> {
    }
  2. 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.

    Repository with Life Cycle Methods Example

    @Repository
    public interface Rectangles {
        @Insert
        Rectangle[] create(Rectangle... r);
    
        @Update
        Rectangle modify(Rectangle r);
    
        @Delete
        void remove(List<Rectangle> r);
    }

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 entity class for the record.

... more details such as the reserved entity name

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants