Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 22 additions & 10 deletions api/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -310,22 +310,29 @@
* <h2>Lifecycle methods</h2>
*
* <p>A lifecycle method makes changes to persistent data in the data store.
* A lifecycle method must be annotated with a lifecycle annotation such as
* {@link Insert}, {@link Update}, {@link Save}, or {@link Delete}. The
* method must accept a single parameter, whose type is either:</p>
* Each lifecycle method of a stateless repository must be annotated with
* a stateless lifecycle annotation, such as {@link Insert}, {@link Update},
* {@link Save}, or {@link Delete}. Each lifecycle method of a
* <a href="../jakarta.data.stateful/">stateful repository</a>
* must be annotated with a stateful lifecycle annotation.
* A lifecycle method, whether stateful or stateless,
* must accept a single parameter, whose type is either:</p>
*
* <ul>
* <li>the class of the entity, or</li>
* <li>{@code List<E>} or {@code E[]} where {@code E} is the class of the
* entities.</li>
* </ul>
*
* <p>The annotated method must be declared {@code void}, or, except in the
* case of {@code @Delete}, have a return type that is the same as the type
* of its parameter.</p>
* <p>The annotated method must be declared {@code void}, or, in cases where
* allowed by the lifecycle annotation, have a return type that is the same
* as the type of its parameter.</p>
*
* <p>A repository without lifecycle methods is considered to be a
* stateless repository.</p>
*
* <table style="width: 100%">
* <caption><b>Lifecycle Annotations</b></caption>
* <caption><b>Stateless Lifecycle Annotations</b></caption>
* <tr style="background-color:#ccc">
* <td style="vertical-align: top; width: 10%"><b>Annotation</b></td>
* <td style="vertical-align: top; width: 25%"><b>Description</b></td>
Expand All @@ -334,7 +341,7 @@
*
* <tr style="vertical-align: top; background-color:#eee"><td>{@link Delete}</td>
* <td>deletes entities</td>
* <td>{@code @Delete}<br>{@code public void remove(person);}</td></tr>
* <td>{@code @Delete}<br>{@code public void delete(person);}</td></tr>
*
* <tr style="vertical-align: top"><td>{@link Insert}</td>
* <td>creates new entities</td>
Expand All @@ -349,8 +356,13 @@
* <td>{@code @Update}<br>{@code public boolean modify(Product modifiedProduct);}</td></tr>
* </table>
*
* <p>Refer to the API documentation for {@link Insert}, {@link Update}, {@link Delete},
* and {@link Save} for further information about these annotations.</p>
* <p>Refer to the API documentation for {@link Insert}, {@link Update},
* {@link Delete}, and {@link Save} for further information about the
* stateless lifecycle annotations.</p>
*
* <p>Refer to the API documentation of the Jakarta Data
* <a href="../jakarta.data.stateful/">Stateful Repositories module</a>
* for additional information about the stateful lifecycle annotations.</p>
*
* <h2>Parameter-based {@code Find} and {@code Delete} methods</h2>
*
Expand Down
2 changes: 1 addition & 1 deletion spec/src/main/asciidoc/repository.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -1007,7 +1007,7 @@ A stateful repository is backed by a _persistence context_, a set of managed ent

- Multiple repositories might share a persistence context, especially if they share a datastore.

- A persistence context is never shared across transactions.
- A persistence context is never shared across transactions that are active at the same time.

A query method of a stateful repository which returns an entity type always returns managed instances belonging to the persistence context associated with the repository.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2025 Contributors to the Eclipse Foundation
* Copyright (c) 2025,2026 Contributors to the Eclipse Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -36,6 +36,12 @@
* database. This typically occurs later, when the persistence context is
* flushed.
* </p>
* <p>To ensure a boundary at which updates are persisted to the data store,
* the application should arrange to have repository methods annotated
* {@code @Merge}, as well as updates made directly to entities, participate
* in a transaction, the duration of which the same persistence context
* applies.
* </p>
* <p>A {@code Merge} method accepts an instance or instances of an entity
* class. The method must have exactly one parameter whose type is either:
* </p>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2025 Contributors to the Eclipse Foundation
* Copyright (c) 2025,2026 Contributors to the Eclipse Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -35,6 +35,11 @@
* when the annotated repository method is invoked, or it might occur later,
* when the persistence context is flushed.
* </p>
* <p>To ensure a boundary at which updates are persisted to the data store,
* the application should arrange to have repository methods annotated
* {@code @Persist} participate in a transaction, the duration of which
* the same persistence context applies.
* </p>
* <p>A {@code Persist} method accepts an instance or instances of an entity
* class. The method must have exactly one parameter whose type is either:
* </p>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2025 Contributors to the Eclipse Foundation
* Copyright (c) 2025,2026 Contributors to the Eclipse Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -33,6 +33,11 @@
* Deletion might occur immediately, when the annotated repository method is
* invoked, or it might occur later, when the persistence context is flushed.
* </p>
* <p>To ensure a boundary at which updates are persisted to the data store,
* the application should arrange to have repository methods annotated
* {@code @Remove} participate in a transaction, the duration of which
* the same persistence context applies.
* </p>
* <p>A {@code Remove} method accepts a managed instance or instances of an
* entity class. The method must have exactly one parameter whose type is
* either:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2026 Contributors to the Eclipse Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* <p>This package provides the lifecycle method annotations for a
* {@linkplain jakarta.data.stateful/ stateful repository}.</p>
*
* @since 1.1
*/
package jakarta.data.repository.stateful;
125 changes: 123 additions & 2 deletions stateful/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2025 Contributors to the Eclipse Foundation
* Copyright (c) 2025,2026 Contributors to the Eclipse Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,8 +16,129 @@
* SPDX-License-Identifier: Apache-2.0
*/

import jakarta.data.metamodel.Attribute;
import jakarta.data.repository.DataRepository;
import jakarta.data.repository.Delete;
import jakarta.data.repository.Insert;
import jakarta.data.repository.Save;
import jakarta.data.repository.Update;
import jakarta.data.repository.stateful.Detach;
import jakarta.data.repository.stateful.Merge;
import jakarta.data.repository.stateful.Persist;
import jakarta.data.repository.stateful.Refresh;
import jakarta.data.repository.stateful.Remove;

/**
* API for Stateful Repositories in Jakarta Data
* <p>API for Stateful Repositories in Jakarta Data</p>
*
* <p>A stateful repository is an interface annotated
* {@link jakarta.data.repository.Repository @Repository} that defines
* at least one stateful lifecycle method. A stateful lifecycle method
* is annotated with exactly one of the following annotations defined in
* the {@link jakarta.data.repository.stateful} package:</p>
*
* <ul>
* <li>{@link Detach @Detach}</li>
* <li>{@link Merge @Merge}</li>
* <li>{@link Persist @Persist}</li>
* <li>{@link Refresh @Refresh}</li>
* <li>{@link Remove @Remove}</li>
* </ul>
*
* <p>Stateful repository interfaces can optionally inherit from the built-in
* {@link DataRepository} interface to define a primary entity class and the
* type of its Id attribute. Otherwise, if all life cycle methods specify the
* same entity class, then the primary entity class is that class.</p>
*
* <p>A stateful repository must not define or inherit any method annotated
* {@link Delete @Delete}, {@link Insert @Insert}, {@link Save @Save}, or
* {@link Update @Update}, which are to be used only on stateless repositories.
* </p>
*
* <h2>Transactions</h2>
*
* <p>To ensure a boundary at which updates are persisted to the data store,
* the application should arrange to have lifecycle methods that cause updates,
* such as those annotated {@code @Merge}, {@code @Persist}, and
* {@code @Remove}, as well as other updates made directly to entities,
* participate in a transaction, the duration of which the same persistence
* context applies. In Jakarta EE environments where resources are capable of
* enlistment, a Jakarta Transactions (JTA) transaction can be used.</p>
*
* <h2>Examples</h2>
*
* <p>The {@linkplain Attribute entity and static metamodel} for the following
* code examples are shown in the {@link Attribute} Javadoc.</p>
*
* <p>A stateful repository interface:
*
* <pre>{@code
* @Repository
* public interface Vehicles extends DataRepository<Car, String> {
* @Persist
* @Transactional
* void persist(Car... cars);
*
* @Refresh
* void refresh(Car car);
*
* @Remove
* void remove(List<Car> cars);
*
* @Find
* List<Car> search(Restriction<Car> filter);
* }}</pre>
* </p>
*
* <p>Application code relying on the
* {@code jakarta.transaction.Transactional} annotation on the example
* {@code persist} method for container-provided transaction management:
*
* <pre>{@code
* @Inject
* Vehicles vehicles;
*
* ...
*
* vehicles.persist(car1, car2, car3);
* }</pre>
* </p>
*
* <p>Application code explicitly managing a transaction covering multiple
* repository operations and updates to entities:
*
* <pre>{@code
* @Resource
* UserTransaction tx;
*
* @Inject
* Vehicles vehicles;
*
* ...
*
* tx.begin();
* try {
* for (Car car : vehicles.search(_Car.price.lessThan(5000))) {
* if (car.price > 1000)
* car.price -= 200;
* else
* scrapList.add(car);
* }
* if (!scrapList.isEmpty)
* vehicles.remove(scrapList);
* } finally {
* if (tx.getStatus() == Status.STATUS_MARKED_ROLLBACK)
* tx.rollback();
* else
* tx.commit();
* }
* }</pre>
* </p>
*
* <p>The Javadoc of the Jakarta Data module provides an
* <a href="../jakarta.data/">overview</a> of Jakarta Data.</p>
*
* @since 1.1
*/
module jakarta.data.stateful {

Expand Down