[Hibernate-JIRA] Created: (HSEARCH-880) Discussion on how to support backward / forward compatible serialization layer
by Emmanuel Bernard (JIRA)
Discussion on how to support backward / forward compatible serialization layer
------------------------------------------------------------------------------
Key: HSEARCH-880
URL: http://opensource.atlassian.com/projects/hibernate/browse/HSEARCH-880
Project: Hibernate Search
Issue Type: New Feature
Components: serialization
Reporter: Emmanuel Bernard
h1. General principles
The serialized message needs the following elements:
* index name: to redirect the flux to the appropriate backend
* serialization provider id: if not present, a cluster must make sure to use the same SerializationProvider for a given IndexManager
* protocol version: today the version is major.minor where the major increase means incompatibility at the stream level, whereas minor means compatibility but with missing features
* stream: this is the SerializationProvider specific byte[]
bq. Do we need a serialization provider id? In other words, do we need to be able to hot-upgrade the SerializationProvider in a cluster?
h1. Exchanging messages in an heterogeneous cluster
h2. Cluster with one way communication (JMS)
In this case the master receives a message and must try and process it.
Receives an index name + serial provider id.
Use the serial provider id to deserialize the message.
If message_major > node_major, the serialization provider fails
If message_minor > node_minor, the serialization provider proceeds but some features might not be supported and the deserialization might fail.
In the minor bump case:
* some feature might not be deserialized and simply ignored. A user is aware of the list of features differences between each node.
* the stream might not be readable by an old version after all due to the use of some new features => Exception
If message_major or message_minor < node_major or node_minor, we use the older protocol deserializer.
bq. could there ever be a problem where a new HSearch Engine cannot deal with an old HSearch engine's message?
h2. Cluster with two way communication (JMS)
Each time a node A needs to send a message to a node B for the first time. It sends the list of supported SerializationProvider id and for each the list of Versions supported. The first SerializationProvider id is preferred and the latest versions are preferred.
A version is more recent if majorA > majorB and with majorA = majorB if minorA > minorB.
Node B receives the handshake message and returns the appropriate serialization provider id and version. Subsequent messages are exchanged with this accepted version between A and B
bq. Is the JGroups clustering using multicast to send change messages ie does it know which node it sends the message to to do the handshake?
bq. What happens if B goes down and back up? Does it have a "new" name that uniquely identify it?
h1. API changes
SerializationProvider will need the following adjustments:
* a getSupportedVersions()
* a getSerializer(Version)
* a getDeserializer(Version)
bq. could it be that Serializer / Deserializer / LuceneWorksBuilder lead to the inability to support a version n-1 (by adding of new methods or stuff like that?
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira
13 years, 2 months
[Hibernate-JIRA] Created: (HSEARCH-841) after deleting an entity lucene index updating fails due to NullPointerException
by Bogdan Butnaru (JIRA)
after deleting an entity lucene index updating fails due to NullPointerException
--------------------------------------------------------------------------------
Key: HSEARCH-841
URL: http://opensource.atlassian.com/projects/hibernate/browse/HSEARCH-841
Project: Hibernate Search
Issue Type: Bug
Components: engine
Affects Versions: 3.4.0.Final
Environment: Hibernate 3.4.0 (on MySQL 5.1.54, but any database is affected AFAIK)
Reporter: Bogdan Butnaru
When entities are deleted, I noticed an exception with a rather large stack trace (below), which appears to be caused by the fact that Lucene is told to remove from the index a document with a null id.
After (quite) a bit of digging, I believe the source is the top of this stack trace:
DocumentBuilderIndexedEntity<T>.getId(Object) line: 662
WorkPlan$PerClassWork<T>.extractProperId(Work<T>) line: 233
WorkPlan$PerClassWork<T>.addWork(Work<T>) line: 205
WorkPlan.addWork(Work<T>) line: 79
WorkQueue.add(Work) line: 73
BatchedQueueingProcessor.add(Work, WorkQueue) line: 115
PostTransactionWorkQueueSynchronization.add(Work) line: 70
TransactionalWorker.performWork(Work<?>, TransactionContext) line: 81
FullTextIndexEventListener.processWork(T, Serializable, WorkType, AbstractEvent, boolean) line: 215
FullTextIndexEventListener.processCollectionEvent(AbstractCollectionEvent) line: 262
FullTextIndexEventListener.onPostRemoveCollection(PostCollectionRemoveEvent) line: 227
CollectionRemoveAction.postRemove() line: 146
CollectionRemoveAction.execute() line: 119
ActionQueue.execute(Executable) line: 273
ActionQueue.executeActions(List) line: 265
ActionQueue.executeActions() line: 186
EJB3FlushEventListener(AbstractFlushingEventListener).performExecutions(EventSource) line: 321
EJB3FlushEventListener(DefaultFlushEventListener).onFlush(FlushEvent) line: 51
SessionImpl.flush() line: 1216
SessionImpl.managedFlush() line: 383
JDBCTransaction.commit() line: 133
TransactionImpl.commit() line: 76
[only application-specific lines below here, omitted]
Specifically, org.hibernate.search.engine.DocumentBuilderIndexedEntity.getId(Object) does:
Object unproxiedEntity = HibernateHelper.unproxy( entity );
return (Serializable) ReflectionHelper.getMemberValue( unproxiedEntity, idGetter );
As far as I can tell, unproxy(entity) will return an entity with a null id if called during postRemove; the returned result is null, although the debugger says that entity.id actually contains the correct (non-null, pre-deletion) value.
org.hibernate.search.engine.WorkPlan.PerClassWork.extractProperId(Work<T>), right below the top of the stack, does:
if ( entity == null || documentBuilder.requiresProvidedId() ||
( work.isIdentifierWasRolledBack() && documentBuilder.isIdMatchingJpaId() )) {
return work.getId();
} else {
return documentBuilder.getId( entity );
}
This condition fails and goes into the "else" block, which is unfortunate, because work.getId() actually contains the correct value.
The error doesn't occur right away: org.hibernate.search.engine.WorkPlan.PerClassWork.addWork(Work<T>) (a bit below the top of the stack) calls "entityById.put( id, entityWork );", with id=null due to the above.
A while later the following happens (the bottom two items are the same as the stack trace above):
DocumentBuilderIndexedEntity<T>.addWorkToQueue(Class<T>, T, Serializable, boolean, boolean, boolean, List<LuceneWork>) line: 355
WorkPlan$PerEntityWork<T>.enqueueLuceneWork(Class<T>, Serializable, AbstractDocumentBuilder<T>, List<LuceneWork>) line: 449
WorkPlan$PerClassWork<T>.enqueueLuceneWork(List<LuceneWork>) line: 250
WorkPlan.getPlannedLuceneWork() line: 150
WorkQueue.prepareWorkPlan() line: 134
BatchedQueueingProcessor.prepareWorks(WorkQueue) line: 124
PostTransactionWorkQueueSynchronization.beforeCompletion() line: 89
EventSourceTransactionContext$DelegateToSynchronizationOnBeforeTx.doBeforeTransactionCompletion(SessionImplementor) line: 172
ActionQueue$BeforeTransactionCompletionProcessQueue.beforeTransactionCompletion() line: 543
ActionQueue.beforeTransactionCompletion() line: 216
SessionImpl.beforeTransactionCompletion(Transaction) line: 571
JDBCContext.beforeTransactionCompletion(Transaction) line: 250
JDBCTransaction.commit() line: 138
TransactionImpl.commit() line: 76
The entry at the top belongs to
public void addWorkToQueue(Class<T> entityClass, T entity, Serializable id, boolean delete, boolean add, boolean batch, List<LuceneWork> queue) {
String idInString = objectToString( idBridge, idKeywordName, id );
if ( delete ) {
queue.add( new DeleteLuceneWork( id, idInString, entityClass ) );
}
if ( add ) {
queue.add( createAddWork( entityClass, entity, id, idInString, HibernateStatelessInitializer.INSTANCE, batch ) );
}
}
The argument delete is true and id is null (it's the value of WorkPlan$PerClassWork<T>.enqueueLuceneWork(List<LuceneWork>) gets it from the documentBuilder.getId(entity) call mentioned above). A little while later the actual exception is triggered:
java.lang.NullPointerException
at org.apache.lucene.index.Term.compareTo(Term.java:115)
at org.apache.lucene.index.TermInfosReader.getIndexOffset(TermInfosReader.java:189)
at org.apache.lucene.index.TermInfosReader.get(TermInfosReader.java:268)
at org.apache.lucene.index.TermInfosReader.get(TermInfosReader.java:208)
at org.apache.lucene.index.SegmentTermDocs.seek(SegmentTermDocs.java:57)
at org.apache.lucene.index.BufferedDeletes.applyDeletes(BufferedDeletes.java:312)
at org.apache.lucene.index.BufferedDeletes.applyDeletes(BufferedDeletes.java:289)
at org.apache.lucene.index.BufferedDeletes.applyDeletes(BufferedDeletes.java:191)
at org.apache.lucene.index.IndexWriter.doFlush(IndexWriter.java:3358)
at org.apache.lucene.index.IndexWriter.flush(IndexWriter.java:3296)
at org.apache.lucene.index.IndexWriter.closeInternal(IndexWriter.java:1836)
at org.apache.lucene.index.IndexWriter.close(IndexWriter.java:1800)
at org.apache.lucene.index.IndexWriter.close(IndexWriter.java:1764)
at org.hibernate.search.backend.Workspace.closeIndexWriter(Workspace.java:244)
at org.hibernate.search.backend.impl.lucene.PerDPQueueProcessor.run(PerDPQueueProcessor.java:113)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
ERROR o.h.s.e.i.LogErrorHandler - Exception occurred java.lang.NullPointerException
Primary Failure:
Entity com.dragg.server.model.Walk Id null Work Type org.hibernate.search.backend.DeleteLuceneWork
Subsequent failures:
Entity com.dragg.server.model.Walk Id null Work Type org.hibernate.search.backend.AddLuceneWork
Entity com.dragg.server.model.Walk Id 5552 Work Type org.hibernate.search.backend.DeleteLuceneWork
java.lang.NullPointerException
at org.apache.lucene.index.Term.compareTo(Term.java:115)
at org.apache.lucene.index.TermInfosReader.getIndexOffset(TermInfosReader.java:189)
at org.apache.lucene.index.TermInfosReader.get(TermInfosReader.java:268)
at org.apache.lucene.index.TermInfosReader.get(TermInfosReader.java:208)
at org.apache.lucene.index.SegmentTermDocs.seek(SegmentTermDocs.java:57)
at org.apache.lucene.index.BufferedDeletes.applyDeletes(BufferedDeletes.java:312)
at org.apache.lucene.index.BufferedDeletes.applyDeletes(BufferedDeletes.java:289)
at org.apache.lucene.index.BufferedDeletes.applyDeletes(BufferedDeletes.java:191)
at org.apache.lucene.index.IndexWriter.doFlush(IndexWriter.java:3358)
at org.apache.lucene.index.IndexWriter.flush(IndexWriter.java:3296)
at org.apache.lucene.index.IndexWriter.closeInternal(IndexWriter.java:1836)
at org.apache.lucene.index.IndexWriter.close(IndexWriter.java:1800)
at org.apache.lucene.index.IndexWriter.close(IndexWriter.java:1764)
at org.hibernate.search.backend.Workspace.closeIndexWriter(Workspace.java:244)
at org.hibernate.search.backend.impl.lucene.PerDPQueueProcessor.run(PerDPQueueProcessor.java:113)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
org.apache.lucene.index.Term.compareTo fails because this.id is null, having received its value a bit earlier from the null document id above. (Technically, I think this also a bug in lucene; surrounding code, for example Term.equals, does test for null, so either Term.compareTo should do it, or the Term should have been checked for null quite a while earlier. Anyway, the results would have been the same, except for easier debugging.)
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira
13 years, 2 months
[Hibernate-JIRA] Created: (HHH-6555) IdClass and mappedBy problem
by Piotr Gliźniewicz (JIRA)
IdClass and mappedBy problem
----------------------------
Key: HHH-6555
URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-6555
Project: Hibernate Core
Issue Type: Bug
Affects Versions: 4.0.0.Beta4, 3.6.6, 4.0.0.Beta2
Environment: Derby 10.8.1.2
Reporter: Piotr Gliźniewicz
I have the following classes:
{code}@Entity
public class SimpleEntity {
@Id
private int id;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "entityA")
private EntityConnection connection;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "entityB")
private List<EntityConnection> otherConnections;
// accessors
}{code}
{code}@Entity
@IdClass(EntityConnectionPK.class)
public class EntityConnection {
@Id
@JoinColumn(name = "entity_a_id")
@OneToOne
private SimpleEntity entityA;
@Id
@JoinColumn(name = "entity_b_id")
@ManyToOne
private SimpleEntity entityB;
// accessors
}{code}
{code}public class EntityConnectionPK implements Serializable {
private int entityA;
private int entityB;
// accessors, equals, hashcode
}{code}
Executing the following query:
{code}
TypedQuery<SimpleEntity> q = em.createQuery("select e from SimpleEntity e where e.id = 1", SimpleEntity.class);
SimpleEntity foundEntity = q.getResultList().get(0);
{code}
results in:
{code}Exception in thread "main" java.lang.NullPointerException
at org.hibernate.persister.entity.AbstractEntityPersister.loadByUniqueKey(AbstractEntityPersister.java:2200)
at org.hibernate.type.EntityType.loadByUniqueKey(EntityType.java:661)
at org.hibernate.type.EntityType.resolve(EntityType.java:441)
at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:150)
at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:1012)
at org.hibernate.loader.Loader.doQuery(Loader.java:889)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:289)
at org.hibernate.loader.Loader.doList(Loader.java:2449)
at org.hibernate.loader.Loader.doList(Loader.java:2435)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2276)
at org.hibernate.loader.Loader.list(Loader.java:2271)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:470)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:355)
at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:196)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1105)
at org.hibernate.internal.QueryImpl.list(QueryImpl.java:100)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:252){code}
After some debugging I found that Hibernate ignores the mappedBy values and uses names with prepended "_identifierMapper". After changing the annotations to:
{code}@Entity
public class SimpleEntity {
@Id
private int id;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "_identifierMapper.entityA")
private EntityConnection connection;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "_identifierMapper.entityB")
private List<EntityConnection> otherConnections;
// accessors
}{/code}
the code works.
Expected: the first example of SimpleEntity should work.
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira
13 years, 2 months
[Hibernate-JIRA] Created: (HHH-3410) @OneToMany forces unique key in @JoinTable when inverseJoinColumns = @JoinColumn(unique=false)
by Kamil Morong (JIRA)
@OneToMany forces unique key in @JoinTable when inverseJoinColumns = @JoinColumn(unique=false)
----------------------------------------------------------------------------------------------
Key: HHH-3410
URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-3410
Project: Hibernate3
Issue Type: Bug
Affects Versions: 3.2.6
Environment: MySQL 5.0.51b, Hibernate Core 3.2.6 GA, Hibernate Annotations 3.3.1 GA
Reporter: Kamil Morong
Hi,
I need to have this class composition with one to many relation:
@Entity
@Table(name="USER")
public class User implements java.io.Serializable {
private Long id;
private String username;
private String password;
private Set<Role> roles = new LinkedHashSet<Role>();
public User() {
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "USER_ID")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name="USERNAME", nullable=false, unique=true)
public String getUsername() {
return username;
}
public void setUsername(String userName) {
this.username = userName;
}
@Column(name="PASSWORD", nullable=false)
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@CollectionOfElements
@OneToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(name = "USER_ROLE",
joinColumns = @JoinColumn(name = "USER_ID", unique=false),
inverseJoinColumns = @JoinColumn(name = "ROLE_ID", unique=false))
@Cascade(org.hibernate.annotations.CascadeType.SAVE_UPDATE)
@LazyCollection(LazyCollectionOption.FALSE)
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
@Entity
@Table(name="ROLE")
public class Role implements java.io.Serializable {
private Long id;
private String name;
public Role() {
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ROLE_ID")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name="NAME", nullable=false, unique=true)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
This will create db tables like SQL script
CREATE TABLE `user` (
`USER_ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
`PASSWORD` VARCHAR(255) NOT NULL DEFAULT '',
`USERNAME` VARCHAR(255) NOT NULL DEFAULT '',
PRIMARY KEY (`USER_ID`),
UNIQUE KEY `USERNAME` (`USERNAME`)
);
CREATE TABLE `role` (
`ROLE_ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
`NAME` VARCHAR(255) NOT NULL DEFAULT '',
PRIMARY KEY (`ROLE_ID`),
UNIQUE KEY `NAME` (`NAME`)
);
CREATE TABLE `user_role` (
`USER_ID` BIGINT(20) NOT NULL,
`ROLE_ID` BIGINT(20) NOT NULL,
PRIMARY KEY (`USER_ID`, `ROLE_ID`),
UNIQUE KEY `ROLE_ID` (`ROLE_ID`),
KEY `FKBC16F46A1174FFAB` (`ROLE_ID`),
KEY `FKBC16F46AB69FC38B` (`USER_ID`),
CONSTRAINT `FKBC16F46AB69FC38B` FOREIGN KEY (`USER_ID`) REFERENCES `user` (`USER_ID`),
CONSTRAINT `FKBC16F46A1174FFAB` FOREIGN KEY (`ROLE_ID`) REFERENCES `role` (`ROLE_ID`)
);
Tables USER and ROLE are right, but the join table USER_ROLE still have defined UNIQUE KEY `ROLE_ID` (`ROLE_ID`).
This causes there cannot be one user with many roles.
There must be some bug while generating database scheme. I am not able to remove unique key.
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators....
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
13 years, 2 months
[Hibernate-JIRA] Created: (HHH-3716) Sybase - null values for columns mapped as "boolean" are persisted as 0 (zero) instead of NULL
by Gail Badner (JIRA)
Sybase - null values for columns mapped as "boolean" are persisted as 0 (zero) instead of NULL
----------------------------------------------------------------------------------------------
Key: HHH-3716
URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-3716
Project: Hibernate Core
Issue Type: Bug
Components: core
Environment: Sybase
Reporter: Gail Badner
Assignee: Gail Badner
Fix For: 3.2.x, 3.3.x, 3.4
Null values for columns mapped as "boolean" are persisted as 0 (zero) instead of NULL. This happens because Hibernate persists a null Boolean value by calling:
PreparedStatement.setNull( index, java.sql.Types.BIT )
The SQL code, java.sql.Types.BIT, is used because the Hibernate BooleanType defines its code as java.sql.Type.BIT.
Sybase JDBC converts the null to 0, apparently because Sybase does not allow nullable bit columns.
This can be reproduced using an annotations unit test, Java5FeaturesTest.testAutoboxing()..
Sybase maps bit columns to tinyint, so when the unit test is executed, the column in the underlying table is actually of type tinyint, not bit. Sybase allows nullable tinyint columns, so there should be no problem persisting a null value as null.
I've verified that changing the call to:
PreparedStatement.setNull( index, java.sql.Types.TINYINT )
persists the null value without being converted to 0.
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators....
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
13 years, 2 months
[Hibernate-JIRA] Created: (HHH-5413) null values for columns mapped as "boolean" cause exception when saving entity with Sybase jdbc4
by Strong Liu (JIRA)
null values for columns mapped as "boolean" cause exception when saving entity with Sybase jdbc4
------------------------------------------------------------------------------------------------
Key: HHH-5413
URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-5413
Project: Hibernate Core
Issue Type: Bug
Components: core
Affects Versions: 3.6.0.Beta1, 3.5.4, 3.5.3
Environment: Sybase jdbc4
Reporter: Strong Liu
ASE doesn't allow 'null' value for 'BIT' datatype;
While performing insert operation using jconn3.jar it permit you to have
'null' value, this 'null' value is converted into bit 0 by jconn3 & hence
ASE doesn't throw any exception;
But incase of jconn4.jar 'null' value is not converted into bit 0, hence
jconn4 directly reports an exception for 'null' value(which is the expected
correct behavior)
Hibernate persists a null Boolean value by calling:
PreparedStatement.setNull( index, java.sql.Types.BIT )
The SQL code, java.sql.Types.BIT, is used because the Hibernate BooleanType defines its code as java.sql.Type.BIT.
This can be reproduced using an annotations unit test, Java5FeaturesTest.testAutoboxing()..
Sybase maps bit columns to tinyint, so when the unit test is executed, the column in the underlying table is actually of type tinyint, not bit. Sybase allows nullable tinyint columns, so there should be no problem persisting a null value as null.
I've verified that changing the call to:
PreparedStatement.setNull( index, java.sql.Types.TINYINT )
persists the null value without being converted to 0.
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators....
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
13 years, 2 months
[Hibernate-JIRA] Created: (HHH-6454) Stafeful, no transaction and persist entity with generatedValue for ID : javax.transaction.InvalidTransactionException: Cannot resume foreign transaction: null
by pierre devreux (JIRA)
Stafeful, no transaction and persist entity with generatedValue for ID : javax.transaction.InvalidTransactionException: Cannot resume foreign transaction: null
----------------------------------------------------------------------------------------------------------------------------------------------------------------
Key: HHH-6454
URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-6454
Project: Hibernate Core
Issue Type: Bug
Components: entity-manager
Affects Versions: 3.6.5, 3.6.3
Environment: OpenEJB 3.2.0,Java 6, Hibernate-entity-manager: 3.6.3, hibernate-validator:4.0.2.
Reporter: pierre devreux
Here my use case :
I have
* a _Service_ entity :
{code:title=Service.java|borderStyle=solid}
@Entity
@TableGenerator(name="ServiceGenerator", pkColumnName="pk_val", pkColumnValue= "service_id", valueColumnName="val",table= "IDENTIFIER")
public class Service {
@Id
@GeneratedValue(generator="ServiceGenerator", strategy=GenerationType.TABLE)
private long id;
private String name;
private String des;
public Service(){};
public Service(String name, String des) {
this.name = name;
this.des = des;
}
}
{code}
* a _ServiceSF / ServiceSFImpl_ stateful :
{code:title=ServiceSFImpl.java|borderStyle=solid}
@Stateful
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class ServiceSFImpl implements ServiceSF {
@PersistenceContext(name="unit", type=PersistenceContextType.EXTENDED)
EntityManager em;
public void persist(Service s) {
em.persist(s);
}
@Remove
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void remove() {
}
}
{code}
* a test
{code:title=Test.java|borderStyle=solid}
...
@Test
public void createServiceSF() throws NamingException {
ServiceSF sf = (ServiceSF) context.lookup("ServiceSFImplLocal");
Service s = new Service("name", desc");
sf.persist(s);
sf.remove();
}
...
{code}
When I launch it, persist method raise an exception : _javax.transaction.InvalidTransactionException: Cannot resume foreign transaction: null_ .
After looking the code, I saw that hibernate starts a new transaction to get the generated ID, and then resume the previous transaction. But in my case there is no transaction, and Hibernate throw an InvalidTransactionException.
Here the complete stack trace :
{code:title=Bar.java|borderStyle=solid}
javax.ejb.EJBException: The bean encountered a non-application exception; nested exception is:
javax.persistence.PersistenceException: org.hibernate.HibernateException: Unable to resume previously suspended transaction
at org.apache.openejb.core.ivm.BaseEjbProxyHandler.convertException(BaseEjbProxyHandler.java:359)
at org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler.java:287)
at $Proxy44.persist(Unknown Source)
at net.atos.od.td.nda.ddd.rt.jee.impl.DomainTransactionImpl.persist(DomainTransactionImpl.java:163)
at net.atos.ddd.test.LauncherTest.createService_aroundBody0(LauncherTest.java:39)
at net.atos.ddd.test.LauncherTest.createService_aroundBody1$advice(LauncherTest.java:31)
at net.atos.ddd.test.LauncherTest.createService(LauncherTest.java:1)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: javax.persistence.PersistenceException: org.hibernate.HibernateException: Unable to resume previously suspended transaction
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1214)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1147)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1153)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:678)
at org.apache.openejb.persistence.JtaEntityManager.persist(JtaEntityManager.java:114)
at net.atos.od.td.nda.ddd.rt.jee.impl.GatewayImpl.persist(GatewayImpl.java:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke(ReflectionInvocationContext.java:162)
at org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed(ReflectionInvocationContext.java:144)
at org.apache.openejb.monitoring.StatsInterceptor.record(StatsInterceptor.java:164)
at org.apache.openejb.monitoring.StatsInterceptor.invoke(StatsInterceptor.java:92)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke(ReflectionInvocationContext.java:162)
at org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed(ReflectionInvocationContext.java:144)
at org.apache.openejb.core.interceptor.InterceptorStack.invoke(InterceptorStack.java:122)
at org.apache.openejb.core.stateful.StatefulContainer.businessMethod(StatefulContainer.java:566)
at org.apache.openejb.core.stateful.StatefulContainer.invoke(StatefulContainer.java:325)
at org.apache.openejb.core.ivm.EjbObjectProxyHandler.businessMethod(EjbObjectProxyHandler.java:217)
at org.apache.openejb.core.ivm.EjbObjectProxyHandler._invoke(EjbObjectProxyHandler.java:77)
at org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler.java:282)
... 32 more
Caused by: org.hibernate.HibernateException: Unable to resume previously suspended transaction
at org.hibernate.engine.transaction.Isolater$JtaDelegate.delegateWork(Isolater.java:147)
at org.hibernate.engine.transaction.Isolater.doIsolatedWork(Isolater.java:67)
at org.hibernate.engine.TransactionHelper.doWorkInNewTransaction(TransactionHelper.java:74)
at org.hibernate.id.MultipleHiLoPerTableGenerator$1.getNextValue(MultipleHiLoPerTableGenerator.java:216)
at org.hibernate.id.enhanced.OptimizerFactory$LegacyHiLoAlgorithmOptimizer.generate(OptimizerFactory.java:351)
at org.hibernate.id.MultipleHiLoPerTableGenerator.generate(MultipleHiLoPerTableGenerator.java:213)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:69)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:179)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:808)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:782)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:786)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:672)
... 54 more
Caused by: javax.transaction.InvalidTransactionException: Cannot resume foreign transaction: null
at org.apache.geronimo.transaction.manager.TransactionManagerImpl.resume(TransactionManagerImpl.java:181)
at org.hibernate.engine.transaction.Isolater$JtaDelegate.delegateWork(Isolater.java:138)
... 68 more
{code}
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira
13 years, 2 months