clarify some javadoc for @Immutable and optimistic locking stuff

This commit is contained in:
Gavin 2022-12-04 12:13:44 +01:00 committed by Gavin King
parent 3c535c544f
commit bdc67f81b1
4 changed files with 38 additions and 24 deletions

View File

@ -13,13 +13,15 @@ import java.lang.annotation.RetentionPolicy;
import static java.lang.annotation.ElementType.*;
/**
* Marks an entity, collection, or attribute as immutable. The absence of this annotation
* means the element is mutable.
* Marks an entity, collection, or attribute of an entity as immutable. The absence of this
* annotation means the element is mutable.
* <ul>
* <li>
* Changes made in memory to the state of an immutable entity are never synchronized to
* the database. The changes are ignored, with no exception thrown. In a mapped inheritance
* hierarchy, {@code @Immutable} may be applied only to the root entity.
* hierarchy, {@code @Immutable} may be applied only to the root entity, and is inherited
* by entity subclasses. To make just one entity in the hierarchy immutable, annotate its
* attributes individually.
* </li>
* <li>
* An immutable collection may not be modified. A {@link org.hibernate.HibernateException}

View File

@ -12,11 +12,14 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specifies whether updating the annotated attribute should trigger an increment
* to the {@link jakarta.persistence.Version version} of the entity instance.
* Specifies whether mutating the annotated attribute should trigger an increment
* to the {@link jakarta.persistence.Version version} of the entity instance. Or,
* if {@link OptimisticLockType#ALL} or {@link OptimisticLockType#DIRTY} are used,
* specifies whether the attribute should be included or excluded from the list of
* checked attributes.
* <p>
* If this annotation is not present, updating an attribute does cause the version
* to be incremented.
* If this annotation is not present, mutating an attribute <em>does</em> cause the
* version to be incremented.
*
* @author Logi Ragnarsson
*/

View File

@ -14,7 +14,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Specifies how optimistic lock checking works for the annotated entity.
* We may detect that an optimistic lock has failed by checking either:
* Optimistic lock checking may detect that an optimistic lock has failed,
* and that the transaction should be aborted, by comparing either:
* <ul>
* <li>the {@linkplain OptimisticLockType#VERSION version or timestamp},
* <li>the {@linkplain OptimisticLockType#DIRTY dirty fields} of the
@ -23,14 +24,22 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* </ul>
* An optimistic lock is usually checked by including a restriction in a
* SQL {@code update} or {@code delete} statement. If the database reports
* that zero rows were updated, we may infer that another transaction has
* already updated or deleted the row, and report the {@linkplain
* jakarta.persistence.OptimisticLockException failure} of the optimistic
* lock.
* that zero rows were updated, it is inferred that another transaction
* has already updated or deleted the row, and the failure of the optimistic
* lock is reported via an {@link jakarta.persistence.OptimisticLockException}.
* <p>
* In an inheritance hierarchy, this annotation may only be applied to the
* root entity, since the optimistic lock checking strategy is inherited
* by entity subclasses.
* <p>
* To exclude a particular attribute from optimistic locking, annotate the
* attribute {@link OptimisticLock @OptimisticLock(excluded=true)}. Then:
* <ul>
* <li>changes to that attribute will never trigger a version increment, and
* <li>the attribute will not be included in the list of fields checked fields
* when {@link OptimisticLockType#ALL} or {@link OptimisticLockType#DIRTY}
* is used.
* </ul>
*
* @author Steve Ebersole
*

View File

@ -381,8 +381,8 @@ public class PropertyBinder {
return property;
}
private void handleNaturalId(Property prop) {
final NaturalId naturalId = property.getAnnotation(NaturalId.class);
private void handleNaturalId(Property property) {
final NaturalId naturalId = this.property.getAnnotation(NaturalId.class);
if ( naturalId != null ) {
if ( !entityBinder.isRootEntity() ) {
throw new AnnotationException( "Property '" + qualify( holder.getPath(), name )
@ -392,27 +392,27 @@ public class PropertyBinder {
if ( !naturalId.mutable() ) {
updatable = false;
}
prop.setNaturalIdentifier( true );
property.setNaturalIdentifier( true );
}
}
private void inferOptimisticLocking(Property prop) {
private void inferOptimisticLocking(Property property) {
// this is already handled for collections in CollectionBinder...
if ( value instanceof Collection ) {
prop.setOptimisticLocked( ((Collection) value).isOptimisticLocked() );
property.setOptimisticLocked( ((Collection) value).isOptimisticLocked() );
}
else if ( property != null && property.isAnnotationPresent(OptimisticLock.class) ) {
final OptimisticLock lockAnn = property.getAnnotation(OptimisticLock.class);
validateOptimisticLock(lockAnn);
prop.setOptimisticLocked( !lockAnn.excluded() );
else if ( this.property != null && this.property.isAnnotationPresent(OptimisticLock.class) ) {
final OptimisticLock optimisticLock = this.property.getAnnotation(OptimisticLock.class);
validateOptimisticLock( optimisticLock );
property.setOptimisticLocked( !optimisticLock.excluded() );
}
else {
prop.setOptimisticLocked( !isToOneValue(value) || insertable ); // && updatable as well???
property.setOptimisticLocked( !isToOneValue(value) || insertable ); // && updatable as well???
}
}
private void validateOptimisticLock(OptimisticLock lockAnn) {
if ( lockAnn.excluded() ) {
private void validateOptimisticLock(OptimisticLock optimisticLock) {
if ( optimisticLock.excluded() ) {
if ( property.isAnnotationPresent(Version.class) ) {
throw new AnnotationException("Property '" + qualify( holder.getPath(), name )
+ "' is annotated '@OptimisticLock(excluded=true)' and '@Version'" );