I want to ask how to audit just a part of a superclass of entity, using hibernate annotations such as @AuditOverride
, @Audited
or else. Right now, I am using hibernate 5.2.12 version.
The annotations I can use only in a sublcass, because the superclass is in other module which shouldn't know anything about submodule.
Superclass contains one List<Items>
and I don't want to it will be audited. Because when I am using one-to-many
relationship I don't want that hibernate will create audit relationship table such as entity1_aud_entity2_aud. I just need entity1_aud and entity2_aud tables.
To refuse the audit relationship table I found two ways, but all of them is not fully correct:
I duplicated the list variable and setters/getters to entity (subclass). And above list variable I write @NotAudited
annotation. To make that annotation working I set access="field"
attribute in hbm
file. So hibernate not using setter and getter to access variable, so the value for the superclass isn't setting during data pulling.
Also I created list entity in which I write @AuditOverrides(value={@AuditOverride(forClass=Entity2.class), @AuditOverride(forClass=Item.class)})
. These annotations creates audit table for list entity. So full code for this auditing way is:
Entity1.class (main sublcass) [hibernate module]
@AuditOverrides(value = {
@AuditOverride(forClass = Entity1.class),
@AuditOverride(forClass = Superclass.class, name = "list", isAudited = false)
})
public class Entity1 extends Superclass {
@NotAudited
private List<Item> list = new ArrayList<>();
@Override
public List<Item> getList() {
return super.getList();
}
@Override
public void setList(List<Item> list) {
super.setList(list);
}
}
Entity1.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="testing.Entity1" table="entity1">
<id name="id" column="id">
<generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
<param name="optimizer">none</param>
<param name="increment_size">1</param>
<param name="sequence_name">seq_entity_main</param>
</generator>
</id>
<list name="list" cascade="all" lazy="false" access="field">
<key>
<column name="entity1_id" index="idx_fk_enm_entity_id"/>
</key>
<list-index>
<column name="list_index"
not-null="true"
default="0"/>
</list-index>
<one-to-many class="testing.Entity2"/>
</list>
<property name="other" column="other" type="string" length="50"/>
</class>
</hibernate-mapping>
Superclass.class [domain module]
public class Superclass extends Builder {
private List<Item> list = new ArrayList<>();
private String other;
public List<Item> getList() {
return list;
}
public void setList(List<Item> list) {
this.list = list;
}
public String getOther() {
return other;
}
public void setOther(String other) {
this.other = other;
}
}
Entity2.class (list item subclass) [hibernate module]
@AuditOverrides({
@AuditOverride(forClass = Entity2.class),
@AuditOverride(forClass = Item.class)})
public class Entity2 extends Item {
}
Entity2.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="testing.Entity2" table="entity2">
<id name="id" column="id">
<generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
<param name="optimizer">none</param>
<param name="increment_size">1</param>
<param name="sequence_name">seq_entity_list</param>
</generator>
</id>
<property name="item" column="item" type="string" length="15"/>
</class>
</hibernate-mapping>
Item.class (list item superclass) [domain module]
public class Item extends Builder {
private String item;
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
}
RESULT:
During data pulling from database only entity1 list will be set. The superclass list will be null, because of access="field"
in hbm file.
I removed access="field"
attribute and started playing only with @AuditOverride
annotations.
If I leave everything as in 1st. way, just remove the access
attribute and the list in entity class, superclass will not be audited at all. So audit table fields will be null.
If I add additional @AuditOverride(forClass=Superclass.class)
- all super class will be audited including the list even @AuditOverride(forClass=Superclass.class, name="list", isAudited=false)
also is written. So I tried modify only:
Entity1.class (sublcass) [hibernate module]
/* @AuditOverrides(value = {
@AuditOverride(forClass = Entity1.class),
@AuditOverride(forClass = Superclass.class, name = "other", isAudited = true),
@AuditOverride(forClass = Superclass.class, name = "list", isAudited = false)
* OR */
@AuditOverrides(value = {
@AuditOverride(forClass = Entity1.class),
@AuditOverride(forClass = Superclass.class),
@AuditOverride(forClass = Superclass.class, name = "list", isAudited = false)
})
public class Entity1 extends Superclass {
}
There is two options and both have same result.
RESULT:
The superclass is audited but the list is also will be audited. So that means that the audit relation ship will be created (entity1_aud_entity2_aud).
The 1st. way is not setting data to the superclass during data pulling. The 2nd. way - auditing all of superclass, while I need just a part of it to be audited. So the question will be:
Is there any other way to use annotations in subclass and audit only just a part of a superclass?
(make sure you read all the question information before the answering)
Thank you
Based on your question, you should be able to annotate your entities as follows:
@Entity
@Audited
@AuditOverrides({
@AuditOverride(forClass = SuperClass.class, isAudited = true),
@AuditOverride(forClass = SuperClass.class, name = "list", isAudited = false)
})
public class Entity1 extends SuperClass {
// just put your entity1 attributes here, no need to duplicate anything
}
@Entity
@Audited
@AuditOverride(forClass = Item.class, isAudited = true)
public class Entity2 extends Item {
// just put your entity2 attributes here, no need to duplicate anything
}
I've only used the @AuditOverride
/ @AuditOverrides
annotations to control the auditing of the super types and their properties and @Audited
to signal that entity type should be audited.
I also illustrate on Entity1
how you can mix various overrides in situations where you want to perhaps audit a majority of properties and exclude a subset or vice versa.
The end result here is that your Entity1_AUD
table will contain all your properties from Entity1
and will also include all properties from your SuperClass
class excluding your list
attribute. Your Entity2_AUD
table will contain all properties from Entity2
and the super class Item
. Additionally, there will be no audited join-table between Entity1
and Entity2
for list
.