How to audit just part of superclass in hibernate?
Asked Answered
L

1

5

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:

1st. way

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.

2nd. way

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).

Conclusion

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

Little answered 23/1, 2018 at 10:0 Comment(0)
E
7

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.

Edra answered 23/1, 2018 at 16:3 Comment(1)
Thanks for your offer. First of as I said for mapping I am using hbm.xml files. The second point is that you offered the same option as my 2nd. way, because isAudited = true attribute is by default true and it can be not specified on this case. How ever, after long messing up I found the way that everything works fine. That means your option (and mine 2nd. way) is correct. And all I need to do to just leave access="field" attribute in entity1.hbm.xml file. So then annotation @AuditOverride(forClass = SuperClass.class, name = "list", isAudited = false) will work correctly.Little

© 2022 - 2024 — McMap. All rights reserved.