{"id":23902950,"url":"https://github.com/mtumilowicz/envers-audited","last_synced_at":"2026-07-20T18:35:53.432Z","repository":{"id":110875359,"uuid":"140898624","full_name":"mtumilowicz/envers-audited","owner":"mtumilowicz","description":"Exploring basic features of @Audited from Hibernate Envers.","archived":false,"fork":false,"pushed_at":"2018-09-27T20:05:19.000Z","size":76,"stargazers_count":1,"open_issues_count":0,"forks_count":2,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-10-10T16:11:32.954Z","etag":null,"topics":["envers","event-sourcing","hibernate-envers"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mtumilowicz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2018-07-13T22:39:55.000Z","updated_at":"2021-07-08T14:27:06.000Z","dependencies_parsed_at":null,"dependency_job_id":"eee7d12c-a478-4b25-b578-a47d2e1facdf","html_url":"https://github.com/mtumilowicz/envers-audited","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mtumilowicz/envers-audited","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fenvers-audited","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fenvers-audited/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fenvers-audited/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fenvers-audited/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mtumilowicz","download_url":"https://codeload.github.com/mtumilowicz/envers-audited/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fenvers-audited/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35696639,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"ssl_error","status_checked_at":"2026-07-20T02:08:09.736Z","response_time":111,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["envers","event-sourcing","hibernate-envers"],"created_at":"2025-01-04T22:51:15.629Z","updated_at":"2026-07-20T18:35:53.408Z","avatar_url":"https://github.com/mtumilowicz.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.com/mtumilowicz/envers-audited.svg?branch=master)](https://travis-ci.com/mtumilowicz/envers-audited)\n\n# envers-audited\nThe main goal of this project is to explore basic features of `@Audited` from `Hibernate Envers`.\n\n_Reference_: [UserGuide documentation](http://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#envers)  \n_Reference_: [JBoss documentation](https://docs.jboss.org/envers/docs/)  \n_Reference_: [Hibernate envers tutorial](https://www.thoughts-on-java.org/hibernate-envers-getting-started/)  \n_Reference_: [Spring Boot rest integration testing](http://www.springboottutorial.com/integration-testing-for-spring-boot-rest-services)\n\n# preface\nYou just need to add the `hibernate-envers.jar` file to the classpath of your application and annotate \nyour entities with `@Audited`. Hibernate will then create a new revision for each transaction and create \na new record in the audit table for each **create**, **update** or **delete** operation performed on an \naudited entity.\n\nYou can then retrieve and query historical data without much effort. Basically, one transaction is one \nrevision. As the revisions are global, having a revision number, you can query for various entities at that \nrevision, retrieving a (partial) view of the database at that revision. You can find a revision number \nhaving a date, and the other way round, you can get the date at which a revision was commited.\n\n# details\n* RevisionEntity (`REVENTITY`)\n\n    |ID   |TIMESTAMP   |ADDITIONAL FIELD (ex. LOGIN)   |\n    |---|---|---|\n    |...   |...   |...   |\n\n* Audit table\n\n    |ID OF SOURCE  |REV (ID FROM REVENTITY)   |REVTYPE   | CUSTOM FIELDS   |\n    |---|---|---|---|\n    |...   |...   |...   |...   |\n\n# manual\n* `pom.xml`\n    ```\n    \u003cdependency\u003e\n        \u003cgroupId\u003eorg.hibernate\u003c/groupId\u003e\n        \u003cartifactId\u003ehibernate-envers\u003c/artifactId\u003e\n        \u003cversion\u003e5.3.2.Final\u003c/version\u003e\n    \u003c/dependency\u003e\n    ```\n    \n* annotate entity with `@Audited`\n    ```\n    @Entity\n    @Data\n    @NoArgsConstructor\n    @AllArgsConstructor\n    @Audited\n    @Builder\n    public class Customer implements Serializable {\n        @Id\n        @GeneratedValue(strategy=GenerationType.AUTO)\n        private Long id;\n        private String firstName;\n        private String lastName;\n    }\n    ```\n    Instead of annotating the whole class and auditing all properties, you can annotate only some \n    persistent properties with `@Audited`. This will cause only these properties to be audited.\n* for above entity will be auto-generated audit table:\n    ```\n    create table Customer_AUD (\n        id bigint not null,\n        REV integer not null,\n        REVTYPE tinyint,\n        firstName varchar(255),\n        lastName varchar(255),\n        primary key (id, REV)\n    )\n    ```\n    The `REVTYPE` column value is taken from the `RevisionType` `Enum`.\n    \n        | Database column value | RevisionType\n        | ----------------------|-------------\n        | 0                     | ADD\n        | 1                     | MOD\n        | 2                     | DEL\n        \n    * **ADD** - indicates that the entity was added (persisted) at that revision.\n    * **DEL** - indicates that the entity was deleted (removed) at that revision.\n    * **MOD** - indicates that the entity was modified (one or more of its fields) at that revision.\n    \n* accessing history  \n    You can access the audit (history) of an entity using the `AuditReader` interface, which you can \n    obtain from an open `EntityManager`:\n    ```\n    AuditReader reader = AuditReaderFactory.get(entityManager);\n    Customer oldCustomer = auditReader.find(Customer.class, customerId, rev)\n    ```\n    it returns an entity with the given primary key, with the data it contained at the given revision. \n    If the entity didn't exist at this revision, `null` is returned.\n    \n* get revisions\n    You can also get a list of revisions at which an entity was modified:\n    ```\n    List\u003cNumber\u003e revisions = auditReader.getRevisions(Customer.class, customerId);\n    ```\n    as well as retrieve the date, at which a revision was created using the `getRevisionDate` method:\n    ```\n    Map\u003cNumber, Date\u003e revisionDatesMap = revisions.stream().collect(Collectors.toMap(Function.identity(), auditReader::getRevisionDate));\n    ```\n    \n* get `Customer` with `id` at revision `rev`\n    ```\n    auditReader.find(Customer.class, id, rev)\n    ```\n    \n# tests\nTests are divided in three sections:\n* junit (`Spock`)\n    * `Controller`\n    * `Service`\n* functional (`Spock`):\n    * `Controller` \u003c-\u003e `Mock(Service)`\n    * `Service` \u003c-\u003e `Mock(Repository)`\n* health-check (`TestRestTemplate`, `jUnit`)\n    * `Controller`\n* integration (`TestRestTemplate`, `jUnit`)\n    * `Controller` \u003c-\u003e `database`\n    \n**Coverage**: `95%`","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtumilowicz%2Fenvers-audited","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmtumilowicz%2Fenvers-audited","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtumilowicz%2Fenvers-audited/lists"}