Skip to content
Merged
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
173 changes: 154 additions & 19 deletions hibernate-core/src/main/java/org/hibernate/annotations/Audited.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.hibernate.cfg.StateManagementSettings;

import java.lang.annotation.Documented;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

Expand Down Expand Up @@ -54,46 +55,180 @@
* the {@linkplain java.time.Instant#now() current JVM instant} is
* used as the transaction identifier, but relying on this default
* behavior is not recommended.
* <p>
* Use the nested {@link Table @Audited.Table} annotation to
* customize the audit log's table name, schema, catalog, or
* column names for the audit log.
*
* @author Gavin King
Comment thread
mbellade marked this conversation as resolved.
*
* @author Marco Belladelli
* @since 7.4
*/
@Documented
@Target({PACKAGE, TYPE, FIELD, METHOD, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Incubating
public @interface Audited {

/**
* The name of the audit log table. Defaults to the
* name of the main table holding currently effective
* data, with the suffix {@code _aud}.
* Excludes the annotated attribute from auditing.
* Updates to an excluded attribute modify the current
* row directly without creating a new revision of the
* entity instance. The audit log table does not contain
* columns mapped by excluded attributes.
*/
String tableName() default "";
@Documented
@Target({FIELD, METHOD})
@Retention(RUNTIME)
@interface Excluded {
}

/**
* The name of the column holding the transaction identifier.
* @see org.hibernate.engine.spi.SharedSessionContractImplementor#getCurrentTransactionIdentifier()
* Specifies the audit log's table mapping for an audited
* entity. Placed on the entity class alongside
* {@link Audited @Audited} to customize the audit table
* name, schema, catalog, and column names.
* <p>
* This annotation may also be placed on a subclass entity
* in a JOINED or TABLE_PER_CLASS hierarchy to override
* the audit table name, schema, or catalog for that
* subclass. The subclass inherits auditing from the root
* entity; the annotation on the subclass only customizes
* table mapping.
*
* @since 7.4
*/
String transactionId() default "REV";
@Documented
@Target({TYPE, PACKAGE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@interface Table {
String DEFAULT_TRANSACTION_ID = "REV";
String DEFAULT_MODIFICATION_TYPE = "REVTYPE";
String DEFAULT_TRANSACTION_END_ID = "REVEND";

/**
* The name of the audit log table. Defaults to the
* name of the main table with the suffix {@code _AUD}.
*/
String name() default "";

/**
* The schema of the audit log table. Defaults to the
* schema of the main table.
*/
String schema() default "";

/**
* The catalog of the audit log table. Defaults to the
* catalog of the main table.
*/
String catalog() default "";

/**
* The name of the column holding the transaction identifier.
*
* @see org.hibernate.engine.spi.SharedSessionContractImplementor#getCurrentTransactionIdentifier()
*/
String transactionIdColumn() default DEFAULT_TRANSACTION_ID;

/**
* The name of the column holding the modification type,
* encoded as 0 for creation, 1 for modification, and 2
* for deletion.
*
* @see org.hibernate.audit.ModificationType
*/
String modificationTypeColumn() default DEFAULT_MODIFICATION_TYPE;

/**
* The name of the column holding the end transaction
* identifier, used only when the
* {@linkplain StateManagementSettings#AUDIT_STRATEGY
* audit strategy} is set to {@code "validity"}. When a
* new audit row is written, the previous row's end
* transaction id column is updated with the current
* transaction identifier, marking it as superseded.
* A {@code null} value indicates the row is current
* (not yet superseded).
*/
String transactionEndIdColumn() default DEFAULT_TRANSACTION_END_ID;

/**
* The name of the column holding the timestamp of the
* end transaction. Only used when the
* {@linkplain StateManagementSettings#AUDIT_STRATEGY
* audit strategy} is set to {@code "validity"} and this
* attribute is set to a non-empty value. Stores the
* timestamp of when the audit row was superseded.
*/
String transactionEndTimestampColumn() default "";
}

/**
* The name of the column holding the modification type,
* encoded as 0 for creation, 1 for modification, and 2
* for deletion
* Specifies a custom audit table name for a
* {@link jakarta.persistence.SecondaryTable @SecondaryTable}.
* Placed on the entity class alongside
* {@link Audited @Audited}.
*
* @since 7.4
*/
String modificationType() default "REVTYPE";
@Documented
@Target(TYPE)
@Retention(RUNTIME)
@Repeatable(SecondaryTables.class)
@interface SecondaryTable {
/**
* The name of the secondary table being overridden.
*/
String secondaryTableName();

/**
* The custom audit table name for this secondary table.
*/
String secondaryAuditTableName();
}

/**
* Excludes the annotated attribute from auditing.
* Updates to an excluded attribute modify the current
* row directly without creating a new revision of the
* entity instance. The audit log table does not contain
* columns mapped by excluded attributes.
* Container for repeatable {@link SecondaryTable} annotations.
*
* @see SecondaryTable
* @since 7.4
*/
@Documented
@Target({FIELD, METHOD})
@Target(TYPE)
@Retention(RUNTIME)
@interface Excluded {
@interface SecondaryTables {
SecondaryTable[] value();
}

/**
* Specifies a custom audit table name (and optionally schema
* and catalog) for an audited collection.
* Placed on the collection field or property.
*
* @since 7.4
*/
@Documented
@Retention(RUNTIME)
@Target({FIELD, METHOD})
@interface CollectionTable {
/**
* The name of the collection audit table.
*/
String name();

/**
* The schema of the collection audit table.
* Defaults to the schema of the owning entity's
* audit table.
*/
String schema() default "";

/**
* The catalog of the collection audit table.
* Defaults to the catalog of the owning entity's
* audit table.
*/
String catalog() default "";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import org.hibernate.Incubating;
import org.hibernate.audit.RevisionListener;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
* Marks an entity as the revision entity for audit logging.
* The annotated class must also be annotated
* {@link jakarta.persistence.Entity @Entity} and must have:
* <ul>
* <li>a field annotated with {@link TransactionId} (typically
* the {@code @Id} with {@code @GeneratedValue})</li>
* <li>a field annotated with {@link Timestamp}</li>
* </ul>
* <p>
* The revision entity is responsible for initializing its own
* {@link Timestamp @Timestamp} field, for example, via a field
* initializer, in the constructor, or in a
* {@link org.hibernate.audit.RevisionListener}.
* <p>
* When a class annotated with {@code @RevisionEntity} is found
* in the domain model, it is automatically configured as the
* {@link org.hibernate.temporal.spi.TransactionIdentifierSupplier},
* and no {@code hibernate.temporal.transaction_id_supplier} setting
* is required.
* <p>
* Only one entity may be annotated with {@code @RevisionEntity}.
*
* @see Audited
* @see TransactionId
* @see Timestamp
* @see RevisionListener
* @since 7.4
*/
@Documented
@Incubating
@Retention(RUNTIME)
@Target(TYPE)
public @interface RevisionEntity {
/**
* An optional {@link RevisionListener} implementation that
* will be called after the revision entity is created, to
* populate custom fields (e.g. user, comment).
*/
Class<? extends RevisionListener> listener() default RevisionListener.class;

/**
* Marks the property that holds the transaction identifier
* in a {@link RevisionEntity @RevisionEntity}. This should
* typically be the auto-generated primary key
* ({@code @Id @GeneratedValue}).
* <p>
* The value is set by the persistence layer when the
* revision entity is inserted.
*
* @see RevisionEntity
* @since 7.4
*/
@Documented
@Retention(RUNTIME)
@Target({ METHOD, FIELD })
@interface TransactionId {
}

/**
* Marks the property that holds the revision timestamp in a
* {@link RevisionEntity @RevisionEntity}. The value must be
* initialized by the revision entity itself, for example,
* via a field initializer, in the constructor, or in a
* {@link org.hibernate.audit.RevisionListener}.
*
* @see RevisionEntity
* @since 7.4
*/
@Documented
@Retention(RUNTIME)
@Target({ METHOD, FIELD })
@interface Timestamp {
}

/**
* Marks a {@code Set<String>} property on a
* {@link RevisionEntity @RevisionEntity} that holds the
* names of entity types modified in each revision. The
* property is typically mapped as an
* {@code @ElementCollection}.
* <p>
* When this annotation is present on a revision entity,
* cross-type revision queries are automatically enabled
* via {@link org.hibernate.audit.AuditLog}.
*
* @see RevisionEntity
* @since 7.4
*/
@Documented
@Retention(RUNTIME)
@Target({ METHOD, FIELD })
@interface ModifiedEntities {
}
}
26 changes: 26 additions & 0 deletions hibernate-core/src/main/java/org/hibernate/audit/AuditEntry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.audit;


/**
* A tuple representing an entity at a specific revision in
* the audit history.
* <p>
* The {@link #revision} field is:
* <ul>
* <li>the revision entity instance (e.g. {@link DefaultRevisionEntity}), if one is configured
* <li>the plain transaction identifier (e.g. {@code Instant}, {@code Integer}) otherwise</li>
* </ul>
*
* @param entity the entity snapshot at this revision
* @param revision the revision entity (if configured) or transaction identifier
* @param modificationType the type of modification (ADD/MOD/DEL)
* @param <T> the entity type
* @author Marco Belladelli
* @since 7.4
*/
public record AuditEntry<T>(T entity, Object revision, ModificationType modificationType) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.audit;

import org.hibernate.HibernateException;

/**
* Indicates a problem related to audit functionality.
*
* @author Marco Belladelli
* @since 7.4
*/
public class AuditException extends HibernateException {
public AuditException(String message) {
super( message );
}

public AuditException(String message, Throwable cause) {
super( message, cause );
}
}
Loading