How to add fields in audit table using Envers in Spring Boot - java

Good morning, how can I add fields in my audit table?
I need to audit some tables, but I need to get the user who did the operation. My entity who will be audited is:
#Entity
#Table(name ="TableName")
#Audited
#AuditTable("TableNameAuditedLog")
public class MyEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "myId")
private Long id;
#Column(name = "myName")
private String name;
}
Looking the docs, I saw an example a custom class to be my audit and a listener, so I made like this:
#Data
#RevisionEntity(AuditListener.class)
#MappedSuperclass
public class Audit {
#Id
#GeneratedValue
#RevisionNumber
private Long id;
#RevisionTimestamp
private Long timestamp;
#Column(name = "user")
private String user;
}
public class AuditListener implements RevisionListener {
#Override
public void newRevision(Object revisionEntity) {
Audit audit = (Audit) revisionEntity;
audit.setUsuario("user");
}
}
I've tried to extends my Audit class in my Entity class, but I'd trouble with JPA, the trouble is:
Caused by: org.hibernate.MappingException: Unable to find column with logical name: myId in org.hibernate.mapping.Table(TableNameAuditedLog) and its related supertables and secondary tables
How can I do this?
Thank you all.

Remove the MappedSuperClass from your Audit class. You could also have Audit extend DefaultRevisionEntity. All you would have in Audit class is your custom field.
#Column(name = "user")
private String user;
A custom audit revision entity:
#Entity
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#RevisionEntity(UserRevisionListener.class)
public class AuditRevisionEntity extends DefaultTrackingModifiedEntitiesRevisionEntity {
private static final long serialVersionUID = 1L;
private Long userId;
#Column(length = 100, nullable = false)
private String initiator;
}
And revision listener
public class UserRevisionListener implements RevisionListener {
private static final String SYSTEM_USER = "System";
private transient final SecurityUtils securityUtils;
public UserRevisionListener(final SecurityUtils securityUtils) {
this.securityUtils = securityUtils;
}
#Override
public void newRevision(Object revisionEntity) {
final AuditRevisionEntity are = (AuditRevisionEntity) revisionEntity;
securityUtils.getPrincipal().ifPresentOrElse((appPrincipal) -> {
are.setUserId(appPrincipal.getUserId());
are.setInitiator(appPrincipal.getDisplayName());
}, () -> are.setInitiator(SYSTEM_USER));
}
}
In my case I am getting the current principal(I am using a custom principal that has the extra fields) using a SecurityUtils helper and setting the AuditRevisionEntity as needed. Some changes are made by Quartz jobs so there is no principal in which case only the initiator is set.

Related

Will the findAll function of Spring Data JPA repository work if the entites are related as many to one or one to one or any such association?

Here is how the entity class looks like
#Entity
public class IndustryCode {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String industryName;
#OneToMany(mappedBy="industryCode")
private Set<CarrierCodes> industryCodes;
#Entity
public class TechCode {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String techName;
#OneToMany(mappedBy="techCode")
private Set<CarrierCodes> techCodes;
#Entity
public class CarrierCodes {
#EmbeddedId
private CarrierCodesId id = new CarrierCodesId();
#ManyToOne
#MapsId("techCodeId")
private TechCode techCode;
#ManyToOne
#MapsId("industryCodeId")
private IndustryCode industryCode;
#SuppressWarnings("serial")
#Embeddable
public class CarrierCodesId implements Serializable {
private Long industryCodeId;
private Long techCodeId;
#Entity
public class Register {
#Id
private Long mobileNumber;
#ManyToOne
// optional but nice to have consistent names
#JoinColumns({
#JoinColumn(name="industryCode_id", referencedColumnName="industryCode_id"),
#JoinColumn(name="techCode_id", referencedColumnName="techCode_id")
)
private CarrierCodes carrierCodes;
}
public class RegisterRepository extends JPARepository<Register,mobileNumber>{
}
My question is if I run findAll on Register table will I get the data for other related tables as well?
I mean using findAll(), will I get a List from which I can take Register obj and use .getCarrierCode().getIndustryCode().getIndustryName() to get industry name corresponding to carrierCode value in Register table

composite key for the table using association annotation

I am new to hibernate and I am trying to implement a basic application that uses this schema (it does not follow the notation I just use it for clarity)
Here is the my classes
#Entity
#Table(name = "race")
public class Race {
#Id
#GeneratedValue
private UUID id;
private String name;
}
#Entity
#Table(name="np_character")
public class NPCharacter {
#Id
#GeneratedValue
private UUID id;
#OneToOne
private Race race;
private String name;
private int age;
}
#Entity
#Table(name="main_female_character")
public class MainFemaleCharacter {
#Id
#GeneratedValue
private UUID id;
#OneToOne
private Race race;
private String name;
private int age;
}
#Entity
#Table(name="copulation_registry")
public class CopulationRegistry {
// ??
private NPCharacter npCharacter;
// ??
private MainFemaleCharacter femCharacter;
private int times;
}
But I ran into the problem with copulation_registry class. I used everywhere OneToOne annotation, instead of using references to keys. But what I should do here? Pairs of id_femPlayer and id_npCharacter are unique.
Should I use EmbeddedId annotation or is it possible somehow to use association annotations to represent the same relation?
You can annotate class CopulationRegistry with #IdClass
#Entity
#IdClass(CopulationRegistryKey.class)
#Table(name="copulation_registry")
public class CopulationRegistry {
#Id
private NPCharacter npCharacter;
#Id
private MainFemaleCharacter femCharacter;
private int times;
}
public class CopulationRegistryKey{
private NPCharacter npCharacter;
private MainFemaleCharacter femCharacter;
}

Spring data with #PrimaryKeyJoinColumn throws Exception

I use Spring data jpa and I have two Entities that have inheritance relationship.
Here is the parent.
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#Table(name = "creditcardinfo")
#DiscriminatorColumn
public class CreditCardInfo implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="credit_card_info_id")
private int creditCardInfoId;
And here is the child
#Entity
#DiscriminatorValue("tappay")
#Table(name = "tappaycardinfo")
#PrimaryKeyJoinColumn(name = "credit_card_info_id",referencedColumnName = "credit_card_info_id")
public class TappayCardInfo extends CreditCardInfo implements Serializable{
private static final long serialVersionUID = 1L;
#Column(name = "card_token")
private String cardToken;
#Column(name = "card_key")
private String cardKey;
And I use JpaRepository to CRUD. Here's my repository.
public interface TappayCardInfoDAO extends JpaRepository<TappayCardInfo, Integer>
I always got an Exception when I saved my TappayCardInfo.
#Inject private TappayCardInfoDAO tappayCardInfoDAO;
...
tappayCardInfoDAO.save(cardInfo);
Here's error message.
Caused by: java.lang.IllegalArgumentException: The entity must have one and only one property with id annotation, class name: base.model.TappayCardInfo

java - Hibernate Search - Unable to perform work. Entity Class is not #Indexed nor hosts #ContainedIn

I have a Spring JPA project with 3 entities: Author, Book and Category.
I want to use Hibernate Search for indexes.
Author class is #Indexed; Book class contains a Category field annotated with #ContainedIn; Category is a very simple class.
CLASS Author
#Entity
#Table
#Indexed
public class Author extends ConcreteEntity {
private static final long serialVersionUID = 1L;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#IndexedEmbedded
private List<Book> books = new ArrayList<>();
}
CLASS Book
#Entity
#Table
public class Book extends ConcreteEntity {
private static final long serialVersionUID = 1L;
#ContainedIn
private Category category;
}
CLASS Category
#Entity
#Table
public class Category extends ConceptEntity {
private static final long serialVersionUID = 1L;
}
CLASS ConcreteEntity and ConceptEntity are similars:
#MappedSuperclass
public abstract class ConcreteEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
private String name;
#Column
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
private String value;
}
#MappedSuperclass
public abstract class ConceptEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
private String name;
#Column
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
private String value;
}
I've got this exception while saving a resource using Hibernate Search.
org.hibernate.search.exception.SearchException: Unable to perform work. Entity Class is not #Indexed nor hosts #ContainedIn: class test.hibernate.search.Category
I don't understand how to solve this issue.
Thanks
Book is not configured correctly. You tell Hibernate Search that Book is included in the Category index (via your #ContainedIn annotation on the category field) but your Category entity is neither marked with #Indexed nor linked to another index via #ContainedIn.
Hibernate Search is just telling you that your configuration doesn't make much sense.
Considering your model, I'm pretty sure you wanted to mark category with #IndexedEmbedded instead.

Hibernate #Where is not enforcing at #MappedSuperClass Entity

For migrating from eclipse link to hibernate, I am looking for the equivalent of eclipse link annotation #AdditionalCriteria in Hibernate at #MappedSupperClass BaseEntity level, to filter logically deleted records from all entities extending this BaseEntity.
I had found #Where annotation. But, this only works at Entity level and not at BaseEntity. Please let me know if there is any possibility to add this or any other Hibernate annotation to filter BaseEntity.
#MappedSuperclass
#Where(clause = "DEL_IND = 0") // DOES NOT WORK
public abstract class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "DEL_IND")
private boolean deleted = Boolean.FALSE;
public boolean getDeleted() {
return deleted;
}
public void setDeleted() {
this.deleted = Boolean.TRUE;
}
}
#Entity
#Table(name = "PERSON")
#Where(clause = "DEL_IND = 0") // THIS WORKS BUT NEEDS TO BE REPEATED IN ALL ENTITIES
public class Person extends BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "PERSON_ID")
private Integer id;
#Column(name = "LAST_NAME")
private String lastName;
#Column(name = "FIRST_NAME")
private String firstName;
--------------------
getters & setters
--------------------
--------------------
}
You can open a Hibernate JIRA issue for this. The only workaround is to manually add the #Where annotation to all your entities or use filters.
With filters you have the option of dynamically enable/disable them, which is useful since you might want to fetch a deleted item sometimes.

Categories