Skip to content

Commit def72ef

Browse files
committed
HHH-17652 Add test for issue
1 parent 8d98dcf commit def72ef

File tree

1 file changed

+204
-0
lines changed

1 file changed

+204
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.envers.integration.manytoone.bidirectional;
6+
7+
import jakarta.persistence.CascadeType;
8+
import jakarta.persistence.Entity;
9+
import jakarta.persistence.EntityManager;
10+
import jakarta.persistence.FetchType;
11+
import jakarta.persistence.GeneratedValue;
12+
import jakarta.persistence.Id;
13+
import jakarta.persistence.JoinColumn;
14+
import jakarta.persistence.ManyToOne;
15+
import jakarta.persistence.OneToMany;
16+
import org.hibernate.envers.AuditReader;
17+
import org.hibernate.envers.Audited;
18+
import org.hibernate.envers.EntityTrackingRevisionListener;
19+
import org.hibernate.envers.RevisionEntity;
20+
import org.hibernate.envers.RevisionListener;
21+
import org.hibernate.envers.RevisionNumber;
22+
import org.hibernate.envers.RevisionTimestamp;
23+
import org.hibernate.envers.RevisionType;
24+
import org.hibernate.orm.test.envers.BaseEnversJPAFunctionalTestCase;
25+
import org.hibernate.orm.test.envers.Priority;
26+
import org.hibernate.testing.orm.junit.Jira;
27+
import org.junit.Test;
28+
29+
import java.util.ArrayList;
30+
import java.util.List;
31+
32+
import static org.assertj.core.api.Assertions.assertThat;
33+
34+
@Jira( "https://hibernate.atlassian.net/browse/HHH-17652" )
35+
public class ManyToOneCustomRevisionListenerTest extends BaseEnversJPAFunctionalTestCase {
36+
private static final ThreadLocal<AuditReader> auditReader = ThreadLocal.withInitial( () -> null );
37+
38+
@Override
39+
protected Class<?>[] getAnnotatedClasses() {
40+
return new Class[] {
41+
Document.class,
42+
DocumentAuthorEmployee.class,
43+
Employee.class,
44+
CustomRevisionEntity.class,
45+
};
46+
}
47+
48+
@Test
49+
@Priority(10)
50+
public void initData() {
51+
// store in thread-local to use it in custom revision listener
52+
auditReader.set( getAuditReader() );
53+
54+
EntityManager em = getEntityManager();
55+
em.getTransaction().begin();
56+
57+
final Employee bilbo = new Employee( "Bilbo Baggins" );
58+
em.persist( bilbo );
59+
final Employee frodo = new Employee( "Frodo Baggins" );
60+
em.persist( frodo );
61+
62+
em.getTransaction().commit();
63+
64+
em.getTransaction().begin();
65+
66+
final Document document = new Document( "The Hobbit" );
67+
document.getAuthors().add( new DocumentAuthorEmployee( 1L, document, bilbo ) );
68+
document.getAuthors().add( new DocumentAuthorEmployee( 2L, document, frodo ) );
69+
em.persist( document );
70+
71+
em.getTransaction().commit();
72+
}
73+
74+
@Test
75+
public void testDocumentAuthorEmployeeRevisions() {
76+
final AuditReader reader = getAuditReader();
77+
assertLastRevision( reader, 1L, "Bilbo Baggins" );
78+
assertLastRevision( reader, 2L, "Frodo Baggins" );
79+
getEntityManager().close();
80+
}
81+
82+
private static void assertLastRevision(AuditReader reader, Long id, String employee) {
83+
final List<Number> revisions = reader.getRevisions( DocumentAuthorEmployee.class, id );
84+
final Number revisionNumber = revisions.get( revisions.size() - 1 );
85+
final DocumentAuthorEmployee result = reader.find( DocumentAuthorEmployee.class, id, revisionNumber );
86+
assertThat( result.getEmployee().getName() ).isEqualTo( employee );
87+
assertThat( result.getDocument().getTitle() ).isEqualTo( "The Hobbit" );
88+
}
89+
90+
@Audited(withModifiedFlag = true)
91+
@Entity(name = "Document")
92+
static class Document {
93+
@Id
94+
@GeneratedValue
95+
private Long id;
96+
97+
private String title;
98+
99+
@OneToMany(mappedBy = "document", cascade = CascadeType.ALL)
100+
private List<DocumentAuthorEmployee> authors = new ArrayList<>();
101+
102+
public Document() {
103+
}
104+
105+
public Document(String title) {
106+
this.title = title;
107+
}
108+
109+
public List<DocumentAuthorEmployee> getAuthors() {
110+
return authors;
111+
}
112+
113+
public String getTitle() {
114+
return title;
115+
}
116+
}
117+
118+
@Audited(withModifiedFlag = true)
119+
@Entity(name = "DocumentAuthorEmployee")
120+
static class DocumentAuthorEmployee {
121+
@Id
122+
private Long id;
123+
124+
@ManyToOne
125+
@JoinColumn(name = "document_id")
126+
private Document document;
127+
128+
@ManyToOne(fetch = FetchType.EAGER)
129+
@JoinColumn(name = "employee_id")
130+
private Employee employee;
131+
132+
public DocumentAuthorEmployee() {
133+
}
134+
135+
public DocumentAuthorEmployee(Long id, Document document, Employee employee) {
136+
this.id = id;
137+
this.document = document;
138+
this.employee = employee;
139+
}
140+
141+
public Long getId() {
142+
return id;
143+
}
144+
145+
public Document getDocument() {
146+
return document;
147+
}
148+
149+
public Employee getEmployee() {
150+
return employee;
151+
}
152+
}
153+
154+
@Audited(withModifiedFlag = true)
155+
@Entity(name = "Employee")
156+
static class Employee {
157+
@Id
158+
@GeneratedValue
159+
private Long id;
160+
161+
private String name;
162+
163+
public Employee() {
164+
}
165+
166+
public Employee(String name) {
167+
this.name = name;
168+
}
169+
170+
public String getName() {
171+
return name;
172+
}
173+
}
174+
175+
@Entity(name = "CustomRevisionEntity")
176+
@RevisionEntity(CustomRevisionListener.class)
177+
static class CustomRevisionEntity {
178+
@Id
179+
@GeneratedValue
180+
@RevisionNumber
181+
private int id;
182+
183+
@RevisionTimestamp
184+
private long timestamp;
185+
}
186+
187+
static class CustomRevisionListener implements RevisionListener, EntityTrackingRevisionListener {
188+
@SuppressWarnings({"unchecked", "rawtypes"})
189+
@Override
190+
public void entityChanged(Class entityClass, String entityName, Object entityId, RevisionType revisionType, Object revisionEntity) {
191+
final AuditReader reader = auditReader.get();
192+
final List<Number> revisions = reader.getRevisions( entityClass, entityId );
193+
final Number revisionNumber = revisions.get( revisions.size() - 1 );
194+
195+
// This is what triggered the NPE
196+
final Object obj = reader.find( entityClass, entityId, revisionNumber );
197+
assertThat( obj ).isNotNull();
198+
}
199+
200+
@Override
201+
public void newRevision(Object revisionEntity) {
202+
}
203+
}
204+
}

0 commit comments

Comments
 (0)