org.hibernate.AssertionFailure: force initializing collection loading - java

After upgraded Spring to v.6 and Spring boot to v.3 (and automatically Hibernate to 6.1.5), tests started to fail because of org.hibernate.AssertionFailure: force initializing collection loading
I have an entity class AClass with a field
#OneToMany(mappedBy = "aClass", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
private Set<BClass> items;
When repository of AClass is triggering several methods, hashCode method is invoked and when it tries to execute items.hashCode(), I'm getting the exception:
2022-12-13T09:42:46.314+01:00 ERROR 15336 --- [ Test worker] org.hibernate.AssertionFailure : HHH000099: an assertion failure occurred (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: force initializing collection loading
org.hibernate.AssertionFailure: force initializing collection loading
at app//org.hibernate.collection.spi.AbstractPersistentCollection.forceInitialization(AbstractPersistentCollection.java:807)
at app//org.hibernate.engine.internal.StatefulPersistenceContext.initializeNonLazyCollections(StatefulPersistenceContext.java:995)
at app//org.hibernate.engine.internal.StatefulPersistenceContext.initializeNonLazyCollections(StatefulPersistenceContext.java:981)
at app//org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:170)
at app//org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:32)
at app//org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:443)
at app//org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.executeQuery(JdbcSelectExecutorStandardImpl.java:166)
at app//org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.list(JdbcSelectExecutorStandardImpl.java:91)
at app//org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:31)
at app//org.hibernate.loader.ast.internal.CollectionLoaderSingleKey.load(CollectionLoaderSingleKey.java:121)
at app//org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:789)
at app//org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:75)
at app//org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:107)
at app//org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:1710)
at app//org.hibernate.collection.spi.AbstractPersistentCollection.lambda$initialize$3(AbstractPersistentCollection.java:613)
at app//org.hibernate.collection.spi.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:265)
at app//org.hibernate.collection.spi.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:611)
at app//org.hibernate.collection.spi.AbstractPersistentCollection.read(AbstractPersistentCollection.java:136)
at app//org.hibernate.collection.spi.PersistentSet.hashCode(PersistentSet.java:407)
at app//xyz.example.AClass.hashCode(AClass.java:52)
...
When I used default Lombok hashCode method, or IntelliJ default like
#Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (x != null ? x.hashCode() : 0);
result = 31 * result + (y != null ? y.hashCode() : 0);
result = 31 * result + (z != null ? z.hashCode() : 0);
result = 31 * result + (items != null ? items.hashCode() : 0);
return result;
}
I'm getting exception, but when I removed this line:
result = 31 * result + (items != null ? items.hashCode() : 0);
tests are passing. However, I wouldn't like to remove items from hashCode method.

Related

JDBi3 UnableToCreateStatementException: No argument factory registered for 'false' of qualified type org.jdbi.v3.core.argument.NullArgument

I'm running into a strange issue where if I try to bind("paramName", false) to a nullable boolean (SQL bit) in my database, I receive the following error:
org.jdbi.v3.core.statement.UnableToCreateStatementException: No argument factory registered for 'false' of qualified type org.jdbi.v3.core.argument.NullArgument [statement:"UPDATE dbo.TagValues SET BoolValue = :boolValue, NumericValue = :numericValue, StringValue = :stringValue WHERE TagID = :tagID", arguments:{positional:{}, named:{stringValue:NULL,tagID:17,numericValue:NULL,boolValue:false}, finder:[]}]
I am using MSSQL Server 2017 and JDBi 3. All 3 of my colon delineated parameters boolValue, numericValue, and stringValue are all nullable.
The weird thing is, I am hardcoding the boolean value, and that is the only instance where the statement seems to barf. I've attached the code, with the offending line. Sorry ahead of time for the line lengths.
PreparedBatch batch = handle.prepareBatch("UPDATE dbo.TagValues SET BoolValue = :boolValue, NumericValue = :numericValue, StringValue = :stringValue WHERE TagID = :tagID");
active_sites.forEach(site -> site.getEntryPoints().forEach(entryPoint -> {
if(entryPoint.isGatewayResponding() && !entryPoint.hasError()){
entryPoint.getTiedTags().forEach(tag -> {
if (boolTypes.contains(tag.getType())) {
batch.bind("boolValue", tag.getValue().getValue()).bindNull("numericValue", Types.FLOAT).bindNull("stringValue", Types.VARCHAR).bind("tagID", tag.getIDX()).add();
}
else if (numericTypes.contains(tag.getType())) {
batch.bindNull("boolValue", Types.BIT).bind("numericValue", tag.getValue().getValue()).bindNull("stringValue", Types.VARCHAR).bind("tagID", tag.getIDX()).add();
}
else if (stringTypes.contains(tag.getType())) {
batch.bindNull("boolValue", Types.BIT).bindNull("numericValue", Types.FLOAT).bind("stringValue", tag.getValue().getValue()).bind("tagID", tag.getIDX()).add();
}
});
}
else {
entryPoint.getTiedTags().forEach(tag -> batch.bindNull("boolValue", Types.BIT).bindNull("numericValue", Types.FLOAT).bindNull("stringValue", Types.VARCHAR).bind("tagID", tag.getIDX()).add());
}
entryPoint.getErrorTags().stream().filter(tag -> tag.getType() == 33 || tag.getType() == 34 || tag.getType() == 35).forEach(tag -> {
if(Objects.nonNull(tag.getValue())) {
batch.bind("boolValue", tag.getValue().getValue()).bindNull("numericValue", Types.FLOAT).bindNull("stringValue", Types.VARCHAR).bind("tagID", tag.getIDX()).add();
}
else {
//TAG 17 FALLS INTO THIS CATEGORY, CONFIRMED BY PRINTLN. THIS IS THE OFFENDER.
batch.bind("boolValue", false).bindNull("numericValue", Types.FLOAT).bindNull("stringValue", Types.VARCHAR).bind("tagID", tag.getIDX()).add();
}
});
}));
Update:
jdbi: 3.18.1
mssql jdbc driver: 9.2.1.jre15
Full stacktrace:
org.jdbi.v3.core.statement.UnableToCreateStatementException: No argument factory registered for 'false' of qualified type org.jdbi.v3.core.argument.NullArgument [statement:"UPDATE dbo.TagValues SET BoolValue = :boolValue, NumericValue = :numericValue, StringValue = :stringValue WHERE TagID = :tagID", arguments:{positional:{}, named:{stringValue:NULL,tagID:17,numericValue:NULL,boolValue:false}, finder:[]}]
at org.jdbi.v3.core.statement.ArgumentBinder.factoryNotFound(ArgumentBinder.java:174)
at org.jdbi.v3.core.statement.ArgumentBinder.lambda$null$2(ArgumentBinder.java:141)
at java.base/java.util.Optional.orElseThrow(Optional.java:403)
at org.jdbi.v3.core.statement.ArgumentBinder.lambda$null$3(ArgumentBinder.java:141)
at org.jdbi.v3.core.statement.ArgumentBinder.lambda$null$4(ArgumentBinder.java:142)
at org.jdbi.v3.core.statement.ArgumentBinder$Prepared.lambda$prepareBinder$12(ArgumentBinder.java:230)
at org.jdbi.v3.core.statement.ArgumentBinder.lambda$wrapExceptions$6(ArgumentBinder.java:153)
at org.jdbi.v3.core.statement.ArgumentBinder$Prepared.lambda$null$13(ArgumentBinder.java:234)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.jdbi.v3.core.statement.ArgumentBinder$Prepared.lambda$prepareBinder$14(ArgumentBinder.java:234)
at org.jdbi.v3.core.statement.ArgumentBinder$Prepared.bindNamed(ArgumentBinder.java:240)
at org.jdbi.v3.core.statement.ArgumentBinder.bind(ArgumentBinder.java:60)
at org.jdbi.v3.core.statement.PreparedBatch.internalBatchExecute(PreparedBatch.java:204)
at org.jdbi.v3.core.statement.PreparedBatch.execute(PreparedBatch.java:108)
at app.dao.services.impl.EntryDaoService.updateTagValues(EntryDaoService.java:165)
at app.SCADA.updateTagValues(SCADA.java:215)
at app.SCADA.run(SCADA.java:93)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
at java.base/java.lang.Thread.run(Thread.java:831)
Update: This was in fact a bug with JDBi where it couldn't bind null to a column for a row or rows when other rows in the same batch have the same parameters and contain data. This was resolved I believe in JDBi 3.24+

Under Spring Boot, Hibernate says a row in table does not exist when it does

I am running a simple query using JPA -> Hibernate -> JDBC -> Oracle.
The query basically is:
select * from mstrgenstate where stateshort='TX';
When I run it at the Oracle Level, I get:
STATEID COUNTRYID STA STATEMED STATELONG
---------- ---------- --- --------------- ------------------------------
1 1 TX Texas Texas
When I run it in Java using JPA and Hibernate, I get that no record exists in the table. The messages I am getting (with the trace set on) are listed below. The entity code (Mstrgenstate.java) was generated using Hibernate. The data-access code (MstrgenstateDAO.java) is using the CrudRepository
Is there some kind of special thing one has to do in order to get data out of the DB?
TIA
Update
I added to the DAO file:
public List<Mstrgenstate> findByStateid ( BigDecimal stateid );
And to the controller:
List<Mstrgenstate> testme = statedao.findByStateid(new BigDecimal(1));
System.out.println("first test here " + testme.size());
I got the following result- it worked
2017-07-21 15:46:13.344 DEBUG 10496 --- [nio-8080-exec-1] org.hibernate.SQL : select mstrgensta0_.stateid as stateid1_6_, mstrgensta0_.countryid as countryid2_6_, mstrgensta0_.statelong as statelong3_6_, mstrgensta0_.statemed as statemed4_6_, mstrgensta0_.stateshort as stateshort5_6_ from oraapps.mstrgenstate mstrgensta0_ where mstrgensta0_.stateid=?
2017-07-21 15:46:13.477 TRACE 10496 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [NUMERIC] - [1]
2017-07-21 15:46:13.487 TRACE 10496 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicExtractor : extracted value ([stateid1_6_] : [NUMERIC]) - [1]
2017-07-21 15:46:13.496 TRACE 10496 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicExtractor : extracted value ([countryid2_6_] : [NUMERIC]) - [1]
2017-07-21 15:46:13.497 TRACE 10496 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicExtractor : extracted value ([statelong3_6_] : [VARCHAR]) - [Texas]
2017-07-21 15:46:13.498 TRACE 10496 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicExtractor : extracted value ([statemed4_6_] : [VARCHAR]) - [Texas]
2017-07-21 15:46:13.498 TRACE 10496 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicExtractor : extracted value ([stateshort5_6_] : [VARCHAR]) - [TX ]
first test here 1
So what I am seeing is that retrieving the data works fine for
integers but when one uses characters, there appears to be some kind
of problem. The DB is Oracle - is there a bug somewhere in all of
this? Below is what I got when I tried to fetch using a string (TX)
messages I am gettting
017-07-21 14:36:42.198 INFO 20212 --- [nio-8080-exec-1] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
2017-07-21 14:36:42.438 DEBUG 20212 --- [nio-8080-exec-1] org.hibernate.SQL : select mstrgensta0_.stateid as stateid1_6_, mstrgensta0_.countryid as countryid2_6_, mstrgensta0_.statelong as statelong3_6_, mstrgensta0_.statemed as statemed4_6_, mstrgensta0_.stateshort as stateshort5_6_ from oraapps.mstrgenstate mstrgensta0_ where mstrgensta0_.stateshort=?
2017-07-21 14:36:42.531 TRACE 20212 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [TX]
2017-07-21 14:36:42.557 DEBUG 20212 --- [nio-8080-exec-1] org.hibernate.SQL : select mstrgensta0_.stateid as stateid1_6_, mstrgensta0_.countryid as countryid2_6_, mstrgensta0_.statelong as statelong3_6_, mstrgensta0_.statemed as statemed4_6_, mstrgensta0_.stateshort as stateshort5_6_ from oraapps.mstrgenstate mstrgensta0_ where mstrgensta0_.statelong=?
2017-07-21 14:36:42.557 TRACE 20212 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [TX]
Fri Jul 21 14:36:42 CDT 2017 => DATA_INPUT_ERROR : => CLASS : CustomerController => EMSG-20008 - finding state id for state name : ->TX<- has failed State passed in TX number of items found 0
ccinfw.messages.DataInputError: Fri Jul 21 14:36:42 CDT 2017 => DATA_INPUT_ERROR : => CLASS : CustomerController => EMSG-20008 - finding state id for state name : ->TX<- has failed State passed in TX number of items found 0
at ccinfw.controller.CustomerController.addCustomer(CustomerController.java:107)
code for controller
#RequestMapping(value = "/add", method = RequestMethod.POST, consumes = "application/json")
public ResponseEntity<Lawncustomer> addCustomer(
#RequestBody CustomerIOPOJO input) throws Exception {
try {
Lawncustomer cust = new Lawncustomer();
cust.setTenantid(input.getTenantid());
cust.setCustomerid(new BigDecimal(200));
cust.setFirstname(input.getFirstname());
cust.setLastname(input.getLastname());
cust.setCellphoneno(input.getCellphoneno());
cust.setEmail(input.getEmail());
cust.setAddress(input.getAddress());
cust.setCity(input.getCity());
if (input.getState() == null
|| input.getState().trim().length() <= 1) {
throw new DataInputError
( " => CLASS : " + this.getClass().getSimpleName()
+ " => EMSG-20000 - invalid state sent in for evaluation - make sure 2-char def is used. Passed in : "
+ input.getState() + " EMail processed " + input.getEmail() );
}
List<Mstrgenstate> statefound;
statefound = statedao.findByStateshort(input.getState());
if (statefound.size() > 1 || statefound.size() < 0 ){
throw new ApplicationError
( " => CLASS : " + this.getClass().getSimpleName()
+ " => EMSG-20012 - invalid number of items found for STATE: ->" + input.getState() + "<- verify DB entries "
+ " State passed in " + input.getState());
}
if (statefound.size() == 0 ) {
statefound = statedao.findByStatelong(input.getState());
if (statefound.size() != 1) {
throw new DataInputError
( " => CLASS : " + this.getClass().getSimpleName()
+ " => EMSG-20008 - finding state id for state name : ->" + input.getState() + "<- has failed "
+ " State passed in " + input.getState() + " number of items found " + statefound.size() );
}
}
cust.setStateid(statefound.get(0).getStateid());
cust.setZipcode(input.getZipcode());
MapFunctionality mapping = new MapFunctionality(input.getAddress(),
input.getCity(), input.getState(), input.getZipcode());
mapping.calcLatLongPositions();
cust.setLoclatitude(mapping.getCalclat());
cust.setLoclongitude(mapping.getCalclon());
customer.save(cust);
return new ResponseEntity<Lawncustomer>(cust, HttpStatus.OK);
} catch (HibernateException e) {
throw new RuntimeError
( " => CLASS : " + this.getClass().getSimpleName()
+ " => EMSG-20010 - finding state id for state name : ->" + input.getState() + "<- has failed "
+ " EMail processed " + input.getEmail());
}
}
MstrgenstateDAO.java (using CrudRepository)
package ccinfw.general.dao;
import java.math.BigDecimal;
import java.util.List;
import javax.transaction.Transactional;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import ccinfw.general.entities.Mstrgenstate;
#Transactional
#Repository
public interface MstrgenstateDAO extends CrudRepository<Mstrgenstate, BigDecimal>{
public List<Mstrgenstate> findByStateshort( String stateshort );
public List<Mstrgenstate> findByStatelong( String statelong );
}
Mstrgenstate.java (generated by Hibernate)
// Generated Jul 16, 2017 9:14:14 AM by Hibernate Tools 4.0.0
import java.math.BigDecimal;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* Mstrgenstate generated by hbm2java
*/
#Entity
#Table(name = "MSTRGENSTATE", schema = "ORAAPPS")
public class Mstrgenstate implements java.io.Serializable {
/**
* serial item added as required
*/
private static final long serialVersionUID = 3354389768807065484L;
private BigDecimal stateid;
private BigDecimal countryid;
private String stateshort;
private String statemed;
private String statelong;
public Mstrgenstate() {
}
public Mstrgenstate(BigDecimal stateid) {
this.stateid = stateid;
}
public Mstrgenstate(BigDecimal stateid, BigDecimal countryid,
String stateshort, String statemed, String statelong) {
this.stateid = stateid;
this.countryid = countryid;
this.stateshort = stateshort;
this.statemed = statemed;
this.statelong = statelong;
}
#Id
#Column(name = "STATEID", unique = true, nullable = false, precision = 22, scale = 0)
public BigDecimal getStateid() {
return this.stateid;
}
public void setStateid(BigDecimal stateid) {
this.stateid = stateid;
}
#Column(name = "COUNTRYID", precision = 22, scale = 0)
public BigDecimal getCountryid() {
return this.countryid;
}
public void setCountryid(BigDecimal countryid) {
this.countryid = countryid;
}
#Column(name = "STATESHORT", length = 3)
public String getStateshort() {
return this.stateshort;
}
public void setStateshort(String stateshort) {
this.stateshort = stateshort;
}
#Column(name = "STATEMED", length = 15)
public String getStatemed() {
return this.statemed;
}
public void setStatemed(String statemed) {
this.statemed = statemed;
}
#Column(name = "STATELONG", length = 30)
public String getStatelong() {
return this.statelong;
}
public void setStatelong(String statelong) {
this.statelong = statelong;
}
}
Nevermind, I just changed the column to VARCHAR and everything worked fine in the DB. I guess the hibernate generation program registered my CHAR(3) to VARCHAR. Silly mistake - mods, you can remove post. Thanks!
Can you make a DESC of your table ?
I Suspect your STATESHORT Column is a CHAR(3) AND not a VARCHAR. The Content of your column is not 'TX' but 'TX ' so the row is not seen.

Java Logger Producing Multiple of the Same Log to Console

I have the following code, we are not using System.out.println statements but have to use a logger to print out to console.
Here is example code (Java):
public void printColumnStats() {
java.util.logging.Logger log = java.util.logging.Logger
.getLogger("ProfileStatusClass");
log.setLevel(Level.ALL);
ConsoleHandler handler = new ConsoleHandler();
handler.setFormatter(new MyFormatter());
handler.setLevel(Level.ALL);
log.addHandler(handler);
// This will print the current Column Profiling stats
log.fine("FieldName : " + this.datasetFieldName);
log.fine("Field index : " + this.fieldIndex);
NumberFormat formatter = new DecimalFormat("#0.00000000");
if (this.fieldType.equalsIgnoreCase("number")) {
log.fine("Field Null Count : " + this.datasetFieldNullCount);
log.fine("Field Valid/Obs Count : " + this.datasetFieldObsCount);
log.fine("Field Min : " + (0l + this.datasetFieldMin));
...
I have the following call for it (sorry this part is in Scala, but should be straight forward:
for (e <- tResults) {
e._2.printColumnStats()
println("++........................................................++")
}
What I am getting tons of repeats before the next set of stats pulls up even though there is just one of each type for the loop:
Field Null Count : 0.0
Field Null Count : 0.0
Field Null Count : 0.0
Field Null Count : 0.0
Field Null Count : 0.0
Field Null Count : 0.0
Field Null Count : 0.0
Field Null Count : 0.0
Field Null Count : 0.0
Field Null Count : 0.0
Field Null Count : 0.0
Field Null Count : 0.0
Field Null Count : 0.0
Field Null Count : 0.0
Field Null Count : 0.0
You are adding a new ConsoleHandler on every call to 'printColumnStats'. You only want to install one handler. If you are going to use code to setup the logger then move the setup code out of the printColumnStats function and into a static block.
private static final Logger log = Logger.getLogger("ProfileStatusClass");
static {
log.setLevel(Level.ALL);
ConsoleHandler handler = new ConsoleHandler();
handler.setFormatter(new MyFormatter());
handler.setLevel(Level.ALL);
log.addHandler(handler);
}
By default, the JVM will install a ConsoleHandler on the root logger too. Your logger should setUserParentHandlers to false so you don't publish to that handler too.

Envers throws RuntimeException in ValidityAuditStrategy when no audit records (table partitioning)

In envers (persistence.xml), I enabled the strategy for table partitioning, according to the development guide: http://docs.jboss.org/hibernate/orm/4.2/devguide/en-US/html/ch15.html#envers-partitioning
The class: ValidityAuditStrategy, throws RuntimeException when there is no audit record. This exception occurs when the Envers try to update an audit record with a date of final revision (revend_tstmp), but this audit record does not exist.
The database of my application receives data load from external applications and is not possible change these external applications to include their audit records.
I have no chance to handle this exception (I don't know how).
In method ValidityAuditStrategy#updateLastRevision:
if (l.size() == 1) {
//... doStuff - OK
} else {
throw new RuntimeException("Cannot find previous revision for entity " + auditedEntityName + " and id " + id);
}
In method ValidityAuditStrategy#perform:
if ( rowCount != 1 )
throw new RuntimeException("Cannot update previous revision for entity " + auditedEntityName + " and id " + id);
A similar issue occurred in this link: https://developer.jboss.org/thread/160195?tstart=0 but had no solution.
It's possible apply a workaround?
I use hibernate-envers-4.1.3-Final version.
Log:
2015-07-17 10:23:28,653 DEBUG [-] [org.hibernate.SQL] (http-/0.0.0.0:8080-5) update MY_ENTITY_AUD set ID_REV_FINAL=?, DATE_HOUR_REV_FINAL=? where ID_ENTITY=? and ID_REV <> ? and ID_REV_FINAL is null
2015-07-17 10:23:28,677 TRACE [-] [org.hibernate.type.descriptor.sql.BasicBinder] (http-/0.0.0.0:8080-5) binding parameter [1] as [INTEGER] - 422
2015-07-17 10:23:28,677 TRACE [-] [org.hibernate.type.descriptor.sql.BasicBinder] (http-/0.0.0.0:8080-5) binding parameter [2] as [TIMESTAMP] - Thu Jul 17 10:23:28 BRT 2015
2015-07-17 10:23:28,677 TRACE [-] [org.hibernate.type.descriptor.sql.BasicBinder] (http-/0.0.0.0:8080-5) binding parameter [3] as [INTEGER] - 12345
2015-07-17 10:23:28,678 TRACE [-] [org.hibernate.type.descriptor.sql.BasicBinder] (http-/0.0.0.0:8080-5) binding parameter [4] as [INTEGER] - 422
2015-07-17 10:23:28,803 ERROR [-] [org.hibernate.AssertionFailure] (http-/0.0.0.0:8080-5) HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): java.lang.RuntimeException: Cannot update previous revision for entity my.package.MyEntity_AUD and id 12345
2015-07-17 10:23:28,841 WARN [-] [com.arjuna.ats.arjuna] (http-/0.0.0.0:8080-5) ARJUNA012125: TwoPhaseCoordinator.beforeCompletion - failed for SynchronizationImple< 0:ffffac1c045d:-3a5600e4:55a7c120:131, org.hibernate.engine.transaction.synchronization.internal.RegisteredSynchronization#5619c5a3 >: org.hibernate.AssertionFailure: Unable to perform beforeTransactionCompletion callback
at org.hibernate.engine.spi.ActionQueue$BeforeTransactionCompletionProcessQueue.beforeTransactionCompletion(ActionQueue.java:754) [hibernate-core-4.1.3-Final.jar:4.1.3-Final]
at org.hibernate.engine.spi.ActionQueue.beforeTransactionCompletion(ActionQueue.java:338) [hibernate-core-4.1.3-Final.jar:4.1.3-Final]
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:490) [hibernate-core-4.1.3-Final.jar:4.1.3-Final]
at org.hibernate.engine.transaction.synchronization.internal.SynchronizationCallbackCoordinatorNonTrackingImpl.beforeCompletion(SynchronizationCallbackCoordinatorNonTrackingImpl.java:114) [hibernate-core-4.1.3-Final.jar:4.1.3-Final]
at org.hibernate.engine.transaction.synchronization.internal.RegisteredSynchronization.beforeCompletion(RegisteredSynchronization.java:53) [hibernate-core-4.1.3-Final.jar:4.1.3-Final]
at com.arjuna.ats.internal.jta.resources.arjunacore.SynchronizationImple.beforeCompletion(SynchronizationImple.java:76)
at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.beforeCompletion(TwoPhaseCoordinator.java:273)
at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.end(TwoPhaseCoordinator.java:93)
at com.arjuna.ats.arjuna.AtomicAction.commit(AtomicAction.java:162)
at com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.java:1189)
at com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.commit(BaseTransaction.java:126)
at com.arjuna.ats.jbossatx.BaseTransactionManagerDelegate.commit(BaseTransactionManagerDelegate.java:75)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.endTransaction(CMTTxInterceptor.java:92) [jboss-as-ejb3-7.4.0.Final-redhat-19.jar:7.4.0.Final-redhat-19]
...
Caused by: java.lang.RuntimeException: Cannot update previous revision for entity entity my.package.MyEntity_AUD and id 12345
at org.hibernate.envers.strategy.ValidityAuditStrategy.perform(ValidityAuditStrategy.java:210) [hibernate-core-4.1.3-Final.jar:4.1.3-Final]
at org.hibernate.envers.synchronization.work.AbstractAuditWorkUnit.perform(AbstractAuditWorkUnit.java:76) [hibernate-core-4.1.3-Final.jar:4.1.3-Final]
at org.hibernate.envers.synchronization.AuditProcess.executeInSession(AuditProcess.java:116) [hibernate-core-4.1.3-Final.jar:4.1.3-Final]
at org.hibernate.envers.synchronization.AuditProcess.doBeforeTransactionCompletion(AuditProcess.java:155) [hibernate-core-4.1.3-Final.jar:4.1.3-Final]
at org.hibernate.envers.synchronization.AuditProcessManager$1.doBeforeTransactionCompletion(AuditProcessManager.java:62) [hibernate-core-4.1.3-Final.jar:4.1.3-Final]
at org.hibernate.engine.spi.ActionQueue$BeforeTransactionCompletionProcessQueue.beforeTransactionCompletion(ActionQueue.java:748) [hibernate-core-4.1.3-Final.jar:4.1.3-Final]
... 90 more
In persistence.xml existing a property to specify a custom AuditStrategey: org.hibernate.envers.audit_strategy.
Change,
From:
<property name="org.hibernate.envers.audit_strategy" value="org.hibernate.envers.strategy.ValidityAuditStrategy"/>
To:
<property name="org.hibernate.envers.audit_strategy" value="com.app.your.pack.YourCustomValidityAuditStrategy"/>
So now you can extend ValidityAuditStrategy and override perform() to not throw a RuntimeException when there is no previous revision for the entity, like this:
public class YourCustomValidityAuditStrategy extends ValidityAuditStrategy {
private final Log logger = LogFactory.getLog(getClass());
#Override
public void perform(Session session, String entityName, AuditConfiguration auditCfg, Serializable id, Object data, Object revision) {
try {
super.perform(session, entityName, auditCfg, id, data, revision);
} catch (RuntimeException re) {
if (logger.isDebugEnabled()) {
logger.debug("IGNORE RuntimeException: Cannot update previous revision for entity.", re);
}
}
}
Overriding just the perform method and catching the RuntimeException won't help you as the code throwing the RuntimeException is enclosed in an anonymous class of type BeforeTransactionCompletionProcess and is executed later.
The ValidityAuditStrategy is not very flexible so the only solution i see is ugly but should work : you must copy the entire ValidityAuditStrategy code in a custom class and catch the RuntimeException in the BeforeTransactionCompletionProcess anonymous class. Then specify your custom class in the persistence.xml :
<property name="org.hibernate.envers.audit_strategy "value="com.app.xxx.CustomValidityAuditStrategy"/>
The perform() method should look like the following :
#Override
public void perform(
final Session session,
final String entityName,
final EnversService enversService,
final Serializable id,
final Object data,
final Object revision) {
final AuditEntitiesConfiguration audEntitiesCfg = enversService.getAuditEntitiesConfiguration();
final String auditedEntityName = audEntitiesCfg.getAuditEntityName( entityName );
final String revisionInfoEntityName = enversService.getAuditEntitiesConfiguration().getRevisionInfoEntityName();
// Save the audit data
session.save( auditedEntityName, data );
// Update the end date of the previous row.
//
// When application reuses identifiers of previously removed entities:
// The UPDATE statement will no-op if an entity with a given identifier has been
// inserted for the first time. But in case a deleted primary key value was
// reused, this guarantees correct strategy behavior: exactly one row with
// null end date exists for each identifier.
final boolean reuseEntityIdentifier = enversService.getGlobalConfiguration().isAllowIdentifierReuse();
if ( reuseEntityIdentifier || getRevisionType( enversService, data ) != RevisionType.ADD ) {
// Register transaction completion process to guarantee execution of UPDATE statement after INSERT.
( (EventSource) session ).getActionQueue().registerProcess( new BeforeTransactionCompletionProcess() {
#Override
public void doBeforeTransactionCompletion(final SessionImplementor sessionImplementor) {
final Queryable productionEntityQueryable = getQueryable( entityName, sessionImplementor );
final Queryable rootProductionEntityQueryable = getQueryable(
productionEntityQueryable.getRootEntityName(), sessionImplementor
);
final Queryable auditedEntityQueryable = getQueryable( auditedEntityName, sessionImplementor );
final Queryable rootAuditedEntityQueryable = getQueryable(
auditedEntityQueryable.getRootEntityName(), sessionImplementor
);
final String updateTableName;
/*commented code*/
...
/*comment the following piece of code*/
/*if ( rowCount != 1 && ( !reuseEntityIdentifier || ( getRevisionType( enversService, data ) != RevisionType.ADD ) ) ) {
throw new RuntimeException(
"Cannot update previous revision for entity " + auditedEntityName + " and id " + id
);
}*/
}
});
}
sessionCacheCleaner.scheduleAuditDataRemoval( session, data );
}
As i said its ugly...
Setting org.hibernate.envers.allow_identifier_reuse: true helped in my scenario.
Not exactly answers the original question, but on the outside looks the same: Cannot update previous revision for entity my.package.MyEntity_AUD and id caa4ce8e.
I am using hibernate-envers-5.4.1 and for whatever reason (probably some buggy import in the past) suddenly faced the same error.
Direct query to the database select * from myentity_aud where id='caa4ce8e' resulted in:
rev revend revtype id ...
2121736 NULL 0 caa4ce8e ...
2121737 NULL 1 caa4ce8e ...
2121738 NULL 1 caa4ce8e ...
-- as seen, revend is NULL for all records.
The issue is: envers expects only one (the latest) to be NULL, all the rest must have the "overriding" rev to be set as revend.
So, to fix this particular case, it was enough to update to:
rev revend revtype id ...
2121736 2121737 0 caa4ce8e ...
2121737 2121738 1 caa4ce8e ...
2121738 NULL 1 caa4ce8e ...
and after that everything worked like a charm.
However, if you have millions of such records, you may want to write some script which will take care of them automatically.

ORA-02289: sequence does not exist when upgrade Hibernate 3 to hibernate 4

I have an issue related to sequence not found when I upgrade hibernate from 3.5 to 4.0.0.RC6:
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:703) [hibernate-core-4.0.0.CR6.jar:4.0.0.CR6]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:707) [hibernate-core-4.0.0.CR6.jar:4.0.0.CR6]
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:847) [hibernate-entitymana
ger-4.0.0.CR6.jar:4.0.0.CR6]
... 159 more
Caused by: java.sql.SQLSyntaxErrorException: ORA-02289: sequence does not exist
at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:91)
at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:133)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:206)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:455)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:413)
at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:1034)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:194)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:791)
at oracle.jdbc.driver.T4CPreparedStatement.executeMaybeDescribe(T4CPreparedStatement.java:866)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1186)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3387)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3431)
Anyone know how to fix it? please let me know. I am using Oracle10gDialect and override getNativeIdentifierGeneratorClass() function by using my own SequenceGenerator. It has worked on Hibernate 3.5 but thrown exception when I upgrade to Hibernate 4.0.0.RC6
Below is my TableNameSequenceGenerator class:
public class TableNameSequenceGenerator extends SequenceGenerator {
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
if(params.getProperty(SEQUENCE) == null || params.getProperty(SEQUENCE).length() == 0) {
String tableName = params.getProperty(PersistentIdentifierGenerator.TABLE);
if(tableName != null) {
String seqName = tableName + "_SEQ";
params.setProperty(SEQUENCE, seqName);
}
}
super.configure(type, params, dialect);
}
}
When I do debugging by using hibernate 4, tableName return REVINFO only (it works in hibernate 3)
Thanks
Hiep
I found the answer.
For common id generator for all classes, we should use
#Id
#GeneratedValue(generator="GENERATOR_COMMON")
#GenericGenerator(name="GENERATOR_COMMON",strategy="point.to.table.generator")
Hope this help someone who have the same issue like me.
Even i got the same issue, Use the following lines
#GenericGenerator(name = "increment", strategy = "increment")
#GeneratedValue(generator = "increment")

Categories

Resources