Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 336731

Summary: Persisting an object that has the same id as a previously existing object in the same inheritance hierarchy causes caching issues
Product: z_Archived Reporter: Adrian Goerler <adrian.goerler>
Component: EclipselinkAssignee: Nobody - feel free to take it <nobody>
Status: NEW --- QA Contact:
Severity: normal    
Priority: P3 CC: eclipselink.orm-inbox, gordon.yorke, konstantin.schwed, krum.tsvetkov, sabine.heider, tom.ware
Version: unspecified   
Target Milestone: ---   
Hardware: PC   
OS: Windows 7   
Whiteboard: test
Attachments:
Description Flags
proposed patch
none
Simple Repro for this bug.
none
Patch avoiding the issue for the bulk of the tests and adding one particular test to reproduce the issue none

Description Adrian Goerler CLA 2011-02-09 11:38:44 EST
Some minor issues prevent the tests in eclipselink.jpa.wdf.test to be executed with shared cache enabled:

- In some tests, the id of a Vehicle entity is assigned manually, although the Vehicle entity has automatic id generation. Vehilce has subclasses Car and Truck. Some tests creates a Car with id=1. The vehicle is cached in the cache with id 1. After the test, the cache content is evicted. Later, a different test created a Truck with id=1. This is not possible any longer as the data structure in the cache assumes that Vehicles with id=1 are Cars, always. 

- The cache content should be evicted before test execution to make tests indenpendent of each other.
Comment 1 Adrian Goerler CLA 2011-02-09 11:49:07 EST
Created attachment 188601 [details]
proposed patch

Proposed patch. Has no effect on test execution with disabled cache. Tested on MySQL: 

cache disabled: OK. 
cache enabled: Fixes the issues described in this bug. No additional test failures.

WDF tests with cache enabled are not productive yet.
Comment 2 Gordon Yorke CLA 2011-05-30 13:40:36 EDT
It would be helpful to know what operations are failing in the test.

The issue here is an Entity is using the same ID as another Entity within the same class hierarchy.  

The other issue is that because EclipseLink has an Object cache and not just a data cache Cache.evict* does not remove the Entity instance from the cache but notifies the cache that the data must be refreshed on next access. To remove the Entity instances, and not just the data, the EclipseLink JPAHelper.getServerSession(entityManagerFactory).getIdentityMapAccessor().initializeAllIdentityMaps() API can be used between single threaded test runs.

Some improvements could be made to invalidation to ensure this issue is resolved.
1 - when invalidated CacheKeys should be removed from any hard caches.
2 - existence checking should check for invalidation if it does not.
3 - based on the failing test EclipseLink's invalidation response could be updated to ensure invalidated CacheKeys did not prevent the desired behaviour.
Comment 3 Adrian Goerler CLA 2011-06-03 04:33:08 EDT
As an example, please consider the following sequence:

// create a car with id=99
em.getTransaction().begin();
Vehicle vehicle = new Car();
vehicle.setId(99);
em.persist(vehicle);
em.getTransaction().commit();
em.clear();

// remove the car again
em.getTransaction().begin();
vehicle = em.find(Vehicle.class, 99);
em.remove(vehicle);
em.getTransaction().commit();
em.clear();
            
// create a bicycle with same id
em.getTransaction().begin();
vehicle = new Bicycle();
vehicle.setId(id);
em.persist(vehicle);
em.getTransaction().commit(); // fails with exception below
em.clear();
            
vehicle = em.find(Vehicle.class, id);

This sequence fails with the following exception:

javax.persistence.RollbackException: Exception [EclipseLink-32] (Eclipse Persistence Services - @VERSION@.@QUALIFIER@): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: Trying to set value [0] for instance variable [numberOfGears] of type [short] in the object.  The specified object is not an instance of the class or interface declaring the underlying field, or an unwrapping conversion has failed.
Internal Exception: java.lang.IllegalArgumentException: Can not set short field org.eclipse.persistence.testing.models.wdf.jpa1.employee.Bicycle.numberOfGears to org.eclipse.persistence.testing.models.wdf.jpa1.employee.Car
Mapping: org.eclipse.persistence.mappings.DirectToFieldMapping[numberOfGears-->TMP_VEHICLE.NUM_GEARS]
Descriptor: RelationalDescriptor(org.eclipse.persistence.testing.models.wdf.jpa1.employee.Bicycle --> [DatabaseTable(TMP_VEHICLE)])
	at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commitInternal(EntityTransactionImpl.java:102)
	at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:63)
	at org.eclipse.persistence.testing.framework.wdf.AbstractBaseTest$ResourceLocalEnvironment.commitTransaction(AbstractBaseTest.java:132)
	at org.eclipse.persistence.testing.framework.wdf.AbstractBaseTest$ResourceLocalEnvironment.commitTransactionAndClear(AbstractBaseTest.java:138)
	at org.eclipse.persistence.testing.tests.wdf.jpa1.inheritance.ChangeSubclassTest.testFindVehicle(ChangeSubclassTest.java:53)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	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.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
	at org.eclipse.persistence.testing.framework.wdf.SkipBugzillaTestRunner.runChild(SkipBugzillaTestRunner.java:184)
	at org.eclipse.persistence.testing.framework.wdf.SkipBugzillaTestRunner.runChild(SkipBugzillaTestRunner.java:38)
	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.runners.ParentRunner.run(ParentRunner.java:236)
	at org.eclipse.persistence.testing.framework.wdf.SkipBugzillaTestRunner.run(SkipBugzillaTestRunner.java:50)
	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: Exception [EclipseLink-32] (Eclipse Persistence Services - @VERSION@.@QUALIFIER@): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: Trying to set value [0] for instance variable [numberOfGears] of type [short] in the object.  The specified object is not an instance of the class or interface declaring the underlying field, or an unwrapping conversion has failed.
Internal Exception: java.lang.IllegalArgumentException: Can not set short field org.eclipse.persistence.testing.models.wdf.jpa1.employee.Bicycle.numberOfGears to org.eclipse.persistence.testing.models.wdf.jpa1.employee.Car
Mapping: org.eclipse.persistence.mappings.DirectToFieldMapping[numberOfGears-->TMP_VEHICLE.NUM_GEARS]
Descriptor: RelationalDescriptor(org.eclipse.persistence.testing.models.wdf.jpa1.employee.Bicycle --> [DatabaseTable(TMP_VEHICLE)])
	at org.eclipse.persistence.exceptions.DescriptorException.illegalArgumentWhileSettingValueThruInstanceVariableAccessor(DescriptorException.java:700)
	at org.eclipse.persistence.internal.descriptors.InstanceVariableAttributeAccessor.setAttributeValueInObject(InstanceVariableAttributeAccessor.java:188)
	at org.eclipse.persistence.mappings.DatabaseMapping.setAttributeValueInObject(DatabaseMapping.java:1428)
	at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.mergeIntoObject(AbstractDirectMapping.java:1097)
	at org.eclipse.persistence.internal.descriptors.ObjectBuilder.mergeIntoObject(ObjectBuilder.java:3444)
	at org.eclipse.persistence.internal.descriptors.ObjectBuilder.mergeChangesIntoObject(ObjectBuilder.java:3381)
	at org.eclipse.persistence.internal.sessions.MergeManager.mergeChangesOfWorkingCopyIntoOriginal(MergeManager.java:748)
	at org.eclipse.persistence.internal.sessions.MergeManager.mergeChangesOfWorkingCopyIntoOriginal(MergeManager.java:623)
	at org.eclipse.persistence.internal.sessions.MergeManager.mergeChanges(MergeManager.java:267)
	at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.mergeChangesIntoParent(UnitOfWorkImpl.java:3246)
	at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.mergeChangesIntoParent(RepeatableWriteUnitOfWork.java:368)
	at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:282)
	at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1135)
	at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commitInternal(EntityTransactionImpl.java:84)
	... 29 more
Caused by: java.lang.IllegalArgumentException: Can not set short field org.eclipse.persistence.testing.models.wdf.jpa1.employee.Bicycle.numberOfGears to org.eclipse.persistence.testing.models.wdf.jpa1.employee.Car
	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source)
	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source)
	at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(Unknown Source)
	at sun.reflect.UnsafeShortFieldAccessorImpl.set(Unknown Source)
	at java.lang.reflect.Field.set(Unknown Source)
	at org.eclipse.persistence.internal.descriptors.InstanceVariableAttributeAccessor.setAttributeValueInObject(InstanceVariableAttributeAccessor.java:141)
	... 41 more


The attribute numberOfGears of the Bicycle cannot be set as the Bicycle used to be a Car (the 2nd level cache used to manage an entity with the same id, which was a Car).
Comment 4 Adrian Goerler CLA 2011-06-03 04:34:23 EDT
Created attachment 197292 [details]
Simple Repro for this bug.
Comment 5 Adrian Goerler CLA 2011-06-08 03:54:33 EDT
Created attachment 197564 [details]
Patch avoiding the issue for the bulk of the tests and adding one particular test to reproduce the issue

This patch fixes the issue for the bulk of the tests (it avoids changing the subclass of a cached entity).

To make sure that the issue is not lost, the test ChangeSubclassTest is added.

Tested on SE/MySQL and JBoss/MySQL
Comment 6 Gordon Yorke CLA 2011-06-08 09:43:30 EDT
This example has nothing to do with the Cache.evict() execution path and behaviour.  It seems EntityManager.remove is not operating correctly and that is a far more severe issue.
Comment 7 Tom Ware CLA 2011-06-08 09:48:31 EDT
Increasing priority.  Requires investigation for 2.3.1 - potential issue with remove.
Comment 8 Tom Ware CLA 2011-08-22 09:39:23 EDT
Changing target and priority.

The fix for bug 336726 will address issues with remove.

The issue with reassigning the same id to a new object in the same hierarchy is not yet addressed.

To investigate this bug, add the attached test and fix any issues.
Comment 9 Eclipse Webmaster CLA 2022-06-09 10:22:18 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink