HHH-17189 Respect Audited annotations in component mapped super types

This commit is contained in:
Chris Cranford 2023-09-09 15:14:11 -04:00 committed by Chris Cranford
parent 1cc7def6f9
commit 586cafa4a1
8 changed files with 499 additions and 0 deletions

View File

@ -114,6 +114,11 @@ public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader {
return true; return true;
} }
// make sure that if a component is annotated with audited, it is honored.
if ( allClassAudited != null ) {
return true;
}
// assumption here is if a component reader is looking at a @MappedSuperclass, it should be treated // assumption here is if a component reader is looking at a @MappedSuperclass, it should be treated
// as not being audited if we have reached htis point; allowing components and any @Embeddable // as not being audited if we have reached htis point; allowing components and any @Embeddable
// class being audited by default. // class being audited by default.

View File

@ -0,0 +1,71 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.orm.test.envers.integration.components.mappedsuperclass;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.MappedSuperclass;
import org.hibernate.envers.Audited;
/**
* @author Chris Cranford
*/
@MappedSuperclass
@Access(AccessType.FIELD)
@Audited
public abstract class AbstractAuditedEmbeddable {
/**
* Initial Value
*/
protected static final int UNDEFINED = -1;
private int code = UNDEFINED;
protected AbstractAuditedEmbeddable() {
this( UNDEFINED );
}
/**
* Constructor with code
*/
public AbstractAuditedEmbeddable(int code) {
this.code = code;
}
public int getCode() {
return code;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + code;
return result;
}
@Override
public boolean equals(Object obj) {
if ( this == obj ) {
return true;
}
if ( obj == null ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}
AbstractAuditedEmbeddable other = (AbstractAuditedEmbeddable) obj;
if ( code != other.code ) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,67 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.orm.test.envers.integration.components.mappedsuperclass;
import jakarta.persistence.Embeddable;
import org.hibernate.envers.Audited;
/**
* @author Chris Cranford
*/
@Embeddable
@Audited
public class AuditedEmbeddableWithDeclaredData extends AbstractAuditedEmbeddable {
private String codeArt;
public AuditedEmbeddableWithDeclaredData(int code, String codeArt) {
super( code );
this.codeArt = codeArt;
}
// Needed for @Embeddable
protected AuditedEmbeddableWithDeclaredData() {
this( UNDEFINED, null );
}
public String getCodeart() {
return codeArt;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ( ( codeArt == null ) ? 0 : codeArt.hashCode() );
return result;
}
@Override
public boolean equals(Object obj) {
if ( this == obj ) {
return true;
}
if ( !super.equals( obj ) ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}
AuditedEmbeddableWithDeclaredData other = (AuditedEmbeddableWithDeclaredData) obj;
if ( codeArt == null ) {
if ( other.codeArt != null ) {
return false;
}
}
else if ( !codeArt.equals( other.codeArt ) ) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,77 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.orm.test.envers.integration.components.mappedsuperclass;
import java.util.List;
import org.hibernate.envers.AuditReader;
import org.hibernate.envers.AuditReaderFactory;
import org.hibernate.orm.test.envers.BaseEnversJPAFunctionalTestCase;
import org.hibernate.orm.test.envers.Priority;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.transaction.TransactionUtil;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Chris Cranford
*/
@JiraKey("HHH-17189")
public class AuditedEmbeddableWithDeclaredDataTest extends BaseEnversJPAFunctionalTestCase {
private long id;
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {
EntityWithAuditedEmbeddableWithDeclaredData.class,
AbstractAuditedEmbeddable.class,
AuditedEmbeddableWithDeclaredData.class
};
}
@Test
@Priority(10)
public void initData() {
this.id = TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
final EntityWithAuditedEmbeddableWithDeclaredData entity = new EntityWithAuditedEmbeddableWithDeclaredData();
entity.setName( "Entity 1" );
entity.setValue( new AuditedEmbeddableWithDeclaredData( 42, "Data" ) );
entityManager.persist(entity);
return entity.getId();
} );
}
@Test
public void testEmbeddableThatExtendsAuditedMappedSuperclass() {
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
final EntityWithAuditedEmbeddableWithDeclaredData entity = entityManager.find(
EntityWithAuditedEmbeddableWithDeclaredData.class,
id
);
final AuditReader auditReader = AuditReaderFactory.get( entityManager );
final List<Number> revisions = auditReader.getRevisions( EntityWithAuditedEmbeddableWithDeclaredData.class, id );
assertThat( revisions ).hasSize( 1 );
final EntityWithAuditedEmbeddableWithDeclaredData entityRevision1 = auditReader.find(
EntityWithAuditedEmbeddableWithDeclaredData.class,
id,
revisions.get( 0 )
);
assertThat( entityRevision1.getName() ).isEqualTo( entity.getName() );
// All fields should be audited because the mapped superclass is annotated
assertThat( entity.getValue().getCodeart() ).isEqualTo( entityRevision1.getValue().getCodeart() );
assertThat( entityRevision1.getValue().getCode() ).isEqualTo( 42 );
} );
}
}

View File

@ -0,0 +1,27 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.orm.test.envers.integration.components.mappedsuperclass;
import jakarta.persistence.Embeddable;
import org.hibernate.envers.Audited;
/**
* @author Chris Cranford
*/
@Embeddable
@Audited
public class AuditedEmbeddableWithNoDeclaredData extends AbstractAuditedEmbeddable {
public AuditedEmbeddableWithNoDeclaredData(int code) {
super( code );
}
// Needed for @Embeddable
protected AuditedEmbeddableWithNoDeclaredData() {
}
}

View File

@ -0,0 +1,76 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.orm.test.envers.integration.components.mappedsuperclass;
import java.util.List;
import org.hibernate.envers.AuditReader;
import org.hibernate.envers.AuditReaderFactory;
import org.hibernate.orm.test.envers.BaseEnversJPAFunctionalTestCase;
import org.hibernate.orm.test.envers.Priority;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.transaction.TransactionUtil;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Chris Cranford
*/
@JiraKey("HHH-17189")
public class AuditedEmbeddableWithNoDeclaredDataTest extends BaseEnversJPAFunctionalTestCase {
private long id;
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {
EntityWithAuditedEmbeddableWithNoDeclaredData.class,
AbstractAuditedEmbeddable.class,
AuditedEmbeddableWithDeclaredData.class
};
}
@Test
@Priority(10)
public void initData() {
this.id = TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
final EntityWithAuditedEmbeddableWithNoDeclaredData entity = new EntityWithAuditedEmbeddableWithNoDeclaredData();
entity.setName( "Entity 1" );
entity.setValue( new AuditedEmbeddableWithNoDeclaredData( 42 ) );
entityManager.persist(entity);
return entity.getId();
} );
}
@Test
public void testEmbeddableThatExtendsAuditedMappedSuperclass() {
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
final EntityWithAuditedEmbeddableWithNoDeclaredData entity = entityManager.find(
EntityWithAuditedEmbeddableWithNoDeclaredData.class,
id
);
final AuditReader auditReader = AuditReaderFactory.get( entityManager );
final List<Number> revisions = auditReader.getRevisions( EntityWithAuditedEmbeddableWithNoDeclaredData.class, id );
assertThat( revisions ).hasSize( 1 );
final EntityWithAuditedEmbeddableWithNoDeclaredData entityRevision1 = auditReader.find(
EntityWithAuditedEmbeddableWithNoDeclaredData.class,
id,
revisions.get( 0 )
);
assertThat( entityRevision1.getName() ).isEqualTo( entity.getName() );
// All fields should be audited because the mapped superclass is annotated
assertThat( entityRevision1.getValue().getCode() ).isEqualTo( 42 );
} );
}
}

View File

@ -0,0 +1,88 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.orm.test.envers.integration.components.mappedsuperclass;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import org.hibernate.envers.Audited;
/**
* @author Chris Cranford
*/
@Entity
@Table(name="EntEmbWAuditedDeclData")
@Access(AccessType.FIELD)
@Audited
public class EntityWithAuditedEmbeddableWithDeclaredData {
@Id
@GeneratedValue
private long id;
@Column(name = "NAME", length = 100)
private String name;
@Embedded
private AuditedEmbeddableWithDeclaredData value;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public AuditedEmbeddableWithDeclaredData getValue() {
return value;
}
public void setValue(AuditedEmbeddableWithDeclaredData value) {
this.value = value;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) ( id ^ ( id >>> 32 ) );
return result;
}
@Override
public boolean equals(Object obj) {
if ( this == obj ) {
return true;
}
if ( obj == null ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}
EntityWithAuditedEmbeddableWithDeclaredData other = (EntityWithAuditedEmbeddableWithDeclaredData) obj;
if ( id != other.id ) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,88 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.orm.test.envers.integration.components.mappedsuperclass;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import org.hibernate.envers.Audited;
/**
* @author Chris Cranford
*/
@Entity
@Table(name="EntEmbWAuditedNoDeclData")
@Access(AccessType.FIELD)
@Audited
public class EntityWithAuditedEmbeddableWithNoDeclaredData {
@Id
@GeneratedValue
private long id;
@Column(name = "NAME", length = 100)
private String name;
@Embedded
private AuditedEmbeddableWithNoDeclaredData value;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public AuditedEmbeddableWithNoDeclaredData getValue() {
return value;
}
public void setValue(AuditedEmbeddableWithNoDeclaredData value) {
this.value = value;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) ( id ^ ( id >>> 32 ) );
return result;
}
@Override
public boolean equals(Object obj) {
if ( this == obj ) {
return true;
}
if ( obj == null ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}
EntityWithAuditedEmbeddableWithNoDeclaredData other = (EntityWithAuditedEmbeddableWithNoDeclaredData) obj;
if ( id != other.id ) {
return false;
}
return true;
}
}