@@ -186,10 +186,39 @@ public interface Objectify
186186 <R > R transactionless (Work <R > work );
187187
188188 /**
189- * <p>Exactly the same behavior as the Work version, but doesn't return anything. Convenient for Java8
190- * so you don't have to return something from the lambda.</p>
189+ * Convenience method that doesn't force you to return something from your lambda.
190+ */
191+ default void transactionless (Runnable work ) {
192+ transactionless ((Work <Void >)() -> {
193+ work .run ();
194+ return null ;
195+ });
196+ }
197+
198+ /**
199+ * <p>Executes work in a transaction with the specified options. If there is already a transaction context,
200+ * that context will be inherited. If there is not already a transaction context, a transaction will be started.</p>
201+ *
202+ * <p>Transaction attributes are set when the transaction is initially started. Even though you can run
203+ * inner transact() blocks, these inner blocks will inherit the outer transaction as-is. You cannot
204+ * change the behavior of a running transaction (though you can suspend it and start a new one).</p>
205+ *
206+ * <p>Within {@code Work.run()}, obtain the correct transactional {@code Objectify} instance by calling
207+ * {@code ObjectifyService.ofy()}</p>
208+ *
209+ * <p>The transaction might retry if there is a concurrency failure; work must be idempotent.</p>
210+ */
211+ <R > R transact (TxnOptions options , Work <R > work );
212+
213+ /**
214+ * Convenience method that doesn't force you to return something from your lambda.
191215 */
192- void transactionless (Runnable work );
216+ default void transact (final TxnOptions options , final Runnable work ) {
217+ transact (options , (Work <Void >)() -> {
218+ work .run ();
219+ return null ;
220+ });
221+ }
193222
194223 /**
195224 * <p>Executes work in a transaction. If there is already a transaction context, that context will be inherited.
@@ -210,7 +239,9 @@ public interface Objectify
210239 * until the full transaction completes normally.
211240 * @return the result of the work
212241 */
213- <R > R transact (Work <R > work );
242+ default <R > R transact (final Work <R > work ) {
243+ return transact (TxnOptions .deflt (), work );
244+ }
214245
215246 /**
216247 * Convenience method that doesn't force you to return something from your lambda.
@@ -223,17 +254,24 @@ default void transact(final Runnable work) {
223254 }
224255
225256 /**
226- * <p>Executes work in a new read-write transaction. Note that this is equivalent to {@code transactNew(Integer.MAX_VALUE, work);}</p>
257+ * <p>Executes work in a NEW transaction with the specified options. If there is already an existing transaction
258+ * running, it is suspended while the new transaction completes.</p>
227259 *
228- * <p>ConcurrentModificationExceptions will cause the transaction to repeat as many times as necessary to
229- * finish the job. Work <b>MUST</b> idempotent. </p>
260+ * <p>Within {@code Work.run()}, obtain the correct transactional {@code Objectify} instance by calling
261+ * {@code ObjectifyService.ofy()} </p>
230262 *
231- * <p>Within {@code Work.run()}, obtain the new transactional {@code Objectify} instance by calling {@code ObjectifyService.ofy()}</p>
263+ * <p>The transaction might retry if there is a concurrency failure; work must be idempotent.</p>
264+ */
265+ <R > R transactNew (TxnOptions options , Work <R > work );
266+
267+ /**
268+ * <p>Executes work in a NEW transaction with the default options.</p>
232269 *
233- * @param work defines the work to be done in a transaction. After the method exits, the transaction will commit.
234- * @return the result of the work
270+ * @see Objectify#transactNew(TxnOptions, Work)
235271 */
236- <R > R transactNew (Work <R > work );
272+ default <R > R transactNew (final Work <R > work ) {
273+ return transactNew (TxnOptions .deflt (), work );
274+ }
237275
238276 /**
239277 * Convenience method that doesn't force you to return something from your lambda.
@@ -246,16 +284,18 @@ default void transactNew(final Runnable work) {
246284 }
247285
248286 /**
249- * <p>Executes the work in a new read-write transaction, repeating up to limitTries times when a ConcurrentModificationException
250- * is thrown. This requires your Work to be idempotent; otherwise limit tries to 1.
287+ * <p>Executes the work in a new read-write transaction, trying up to limitTries times when a concurrency
288+ * failure happens.</p>
251289 *
252290 * <p>Within {@code Work.run()}, obtain the new transactional {@code Objectify} instance by calling {@code ObjectifyService.ofy()}</p>
253291 *
254292 * @param limitTries is the max # of tries. Must be > 0. A value of 1 means "try only once".
255293 * @param work defines the work to be done in a transaction. After the method exits, the transaction will commit.
256294 * @return the result of the work
257295 */
258- <R > R transactNew (int limitTries , Work <R > work );
296+ default <R > R transactNew (final int limitTries , final Work <R > work ) {
297+ return transactNew (TxnOptions .deflt ().limitTries (limitTries ), work );
298+ }
259299
260300 /**
261301 * Convenience method that doesn't force you to return something from your lambda.
@@ -279,9 +319,11 @@ default void transactNew(int limitTries, Runnable work) {
279319 * <p>Within {@code Work.run()}, obtain the correct transactional {@code Objectify} instance by calling
280320 * {@code ObjectifyService.ofy()}</p>
281321 *
282- * <p>Readonly transactions do not retry.</p>
322+ * <p>Readonly transactions do not have concurrency failures and do not retry.</p>
283323 */
284- <R > R transactReadOnly (Work <R > work );
324+ default <R > R transactReadOnly (final Work <R > work ) {
325+ return transact (TxnOptions .deflt ().readOnly (true ), work );
326+ }
285327
286328 /**
287329 * Convenience method that doesn't force you to return something from your lambda.
@@ -313,10 +355,14 @@ default void transactReadOnly(final Runnable work) {
313355 <R > R execute (TxnType txnType , Work <R > work );
314356
315357 /**
316- * <p>Exactly the same behavior as the Work version, but doesn't return anything. Convenient for Java8
317- * so you don't have to return something from the lambda.</p>
358+ * Convenience method that doesn't force you to return something from your lambda.
318359 */
319- void execute (TxnType txnType , Runnable work );
360+ default void execute (final TxnType txnType , final Runnable work ) {
361+ execute (txnType , (Work <Void >)() -> {
362+ work .run ();
363+ return null ;
364+ });
365+ }
320366
321367 /**
322368 * Synchronously flushes any deferred operations to the datastore. Objectify does this for you at the end
0 commit comments