Community
Participate
Working Groups
with eclipselink 2.2.0-RC3/ 2.2.0/ 2.3.0-RC1 the descriptor between an entity and its embedded objects are incorrect if some entities are not cached. if all entites are cached or if none are cached then there is no problem. in 2.1.3 it's ok. I have been unable to create reproduce the problem in anything other than our full code base so cant post a recreation. see http://www.eclipse.org/forums/index.php/t/209146/ for previous discussions and attachment eclipselink-caching-embedding.txt for details. apparently this may be something to do with the new protected cache support in 2.2.
Created attachment 196558 [details] details of cache settings and eclipselink versions
Created attachment 196559 [details] Example of entity classes used
Changed to critical, we can't use eclipselink while this problem is evident
Setting target to 2.2.1 as this appears to be a regression in 2.2
I can force a similar exception in a slightly different manner than described in the attachments. I add a OneToOneMapping to another Entity from Country and make the new Entity, and only the new Entity not use a shared cache. @OneToOne private Foo foo = null; <property name="eclipselink.cache.shared.default" value="true"/> <property name="eclipselink.cache.shared.Foo" value="false"/> I then put a populated country in the database, clear the cache and reread it using a read-only find. Map properties = new HashMap(); properties.put(QueryHints.READ_ONLY, "true"); country = em.find(Country.class, "myId", properties); The exception and stacktrace mimics the one posted in the bug almost perfectly. I have not been able to get this exception with a non-read-only query, but it is possible that some, more complex set of mappings could result here. The key code is in AbstractDirectMapping.valueFromRow: if (this.descriptor.isProtectedIsolation()) { if (this.isCacheable && isTargetProtected && cacheKey != null) { Object cached = cacheKey.getObject(); if (cached != null) { if (wasCacheUsed != null){ wasCacheUsed[0] = Boolean.TRUE; } Object attributeValue = getAttributeValueFromObject(cached); return buildCloneValue(attributeValue, executionSession); } } } Here we're trying to use the cached data to build mappings from the embeddable into the object we will return. The problem is that the cache key we use to build the data represents to owning object and not the embeddable. Workarounds are listed throughout the bug, but basically relate to not using protected isolation with embeddables in certain circumstances. For me, read-only queries are the only thing that should obviously be avoided, but it is possible there are other scenarios. Here's the exception I get: [EL Warning]: 2011-06-13 15:18:54.523--ClientSession(30102190)--Thread(Thread[main,5,main])--Local Exception Stack: Exception [EclipseLink-26] (Eclipse Persistence Services - @VERSION@.@QUALIFIER@): org.eclipse.persistence.exceptions.DescriptorException Exception Description: Trying to get value for instance variable [auditDateTime] of type [java.sql.Timestamp] from the object [foo.Country]. The specified object is not an instance of the class or interface declaring the underlying field. Internal Exception: java.lang.IllegalArgumentException: Can not set java.sql.Timestamp field foo.LiveFields.auditDateTime to foo.Country Mapping: org.eclipse.persistence.mappings.DirectToFieldMapping[auditDateTime-->COUNTRY.AUDITDATETIME] Descriptor: RelationalDescriptor(foo.LiveFields --> [DatabaseTable(COUNTRY)]) at org.eclipse.persistence.exceptions.DescriptorException.illegalArgumentWhileGettingValueThruInstanceVariableAccessor(DescriptorException.java:645) at org.eclipse.persistence.internal.descriptors.InstanceVariableAttributeAccessor.getAttributeValueFromObject(InstanceVariableAttributeAccessor.java:79) at org.eclipse.persistence.mappings.DatabaseMapping.getAttributeValueFromObject(DatabaseMapping.java:523) at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.valueFromRow(AbstractDirectMapping.java:1276) at org.eclipse.persistence.mappings.DatabaseMapping.readFromRowIntoObject(DatabaseMapping.java:1325) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildAttributesIntoObject(ObjectBuilder.java:344) at org.eclipse.persistence.mappings.AggregateObjectMapping.buildAggregateFromRow(AggregateObjectMapping.java:377) at org.eclipse.persistence.mappings.AggregateObjectMapping.readFromRowIntoObject(AggregateObjectMapping.java:1430) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildAttributesIntoObject(ObjectBuilder.java:344) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildProtectedObject(ObjectBuilder.java:821) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:657) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:499) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:456) at org.eclipse.persistence.queries.ObjectLevelReadQuery.buildObject(ObjectLevelReadQuery.java:723) at org.eclipse.persistence.queries.ReadObjectQuery.executeObjectLevelReadQuery(ReadObjectQuery.java:453) at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1080) at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:808) at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1040) at org.eclipse.persistence.queries.ReadObjectQuery.execute(ReadObjectQuery.java:412) at org.eclipse.persistence.internal.sessions.AbstractSession.internalExecuteQuery(AbstractSession.java:2800) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1521) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1503) at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1124) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2842) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1521) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1503) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1463) at org.eclipse.persistence.internal.jpa.EntityManagerImpl.executeQuery(EntityManagerImpl.java:781) at org.eclipse.persistence.internal.jpa.EntityManagerImpl.findInternal(EntityManagerImpl.java:725) at org.eclipse.persistence.internal.jpa.EntityManagerImpl.find(EntityManagerImpl.java:619) at org.eclipse.persistence.internal.jpa.EntityManagerImpl.find(EntityManagerImpl.java:521) at test.Test.main(Test.java:40) Caused by: java.lang.IllegalArgumentException: Can not set java.sql.Timestamp field foo.LiveFields.auditDateTime to foo.Country at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146) at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150) at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:37) at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:18) at java.lang.reflect.Field.get(Field.java:358) at org.eclipse.persistence.internal.descriptors.InstanceVariableAttributeAccessor.getAttributeValueFromObject(InstanceVariableAttributeAccessor.java:76) ... 30 more Exception in thread "main" Local Exception Stack: Exception [EclipseLink-26] (Eclipse Persistence Services - @VERSION@.@QUALIFIER@): org.eclipse.persistence.exceptions.DescriptorException Exception Description: Trying to get value for instance variable [auditDateTime] of type [java.sql.Timestamp] from the object [foo.Country]. The specified object is not an instance of the class or interface declaring the underlying field. Internal Exception: java.lang.IllegalArgumentException: Can not set java.sql.Timestamp field foo.LiveFields.auditDateTime to foo.Country Mapping: org.eclipse.persistence.mappings.DirectToFieldMapping[auditDateTime-->COUNTRY.AUDITDATETIME] Descriptor: RelationalDescriptor(foo.LiveFields --> [DatabaseTable(COUNTRY)]) at org.eclipse.persistence.exceptions.DescriptorException.illegalArgumentWhileGettingValueThruInstanceVariableAccessor(DescriptorException.java:645) at org.eclipse.persistence.internal.descriptors.InstanceVariableAttributeAccessor.getAttributeValueFromObject(InstanceVariableAttributeAccessor.java:79) at org.eclipse.persistence.mappings.DatabaseMapping.getAttributeValueFromObject(DatabaseMapping.java:523) at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.valueFromRow(AbstractDirectMapping.java:1276) at org.eclipse.persistence.mappings.DatabaseMapping.readFromRowIntoObject(DatabaseMapping.java:1325) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildAttributesIntoObject(ObjectBuilder.java:344) at org.eclipse.persistence.mappings.AggregateObjectMapping.buildAggregateFromRow(AggregateObjectMapping.java:377) at org.eclipse.persistence.mappings.AggregateObjectMapping.readFromRowIntoObject(AggregateObjectMapping.java:1430) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildAttributesIntoObject(ObjectBuilder.java:344) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildProtectedObject(ObjectBuilder.java:821) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:657) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:499) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:456) at org.eclipse.persistence.queries.ObjectLevelReadQuery.buildObject(ObjectLevelReadQuery.java:723) at org.eclipse.persistence.queries.ReadObjectQuery.executeObjectLevelReadQuery(ReadObjectQuery.java:453) at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1080) at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:808) at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1040) at org.eclipse.persistence.queries.ReadObjectQuery.execute(ReadObjectQuery.java:412) at org.eclipse.persistence.internal.sessions.AbstractSession.internalExecuteQuery(AbstractSession.java:2800) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1521) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1503) at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1124) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2842) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1521) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1503) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1463) at org.eclipse.persistence.internal.jpa.EntityManagerImpl.executeQuery(EntityManagerImpl.java:781) at org.eclipse.persistence.internal.jpa.EntityManagerImpl.findInternal(EntityManagerImpl.java:725) at org.eclipse.persistence.internal.jpa.EntityManagerImpl.find(EntityManagerImpl.java:619) at org.eclipse.persistence.internal.jpa.EntityManagerImpl.find(EntityManagerImpl.java:521) at test.Test.main(Test.java:40) Caused by: java.lang.IllegalArgumentException: Can not set java.sql.Timestamp field foo.LiveFields.auditDateTime to foo.Country at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146) at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150) at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:37) at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:18) at java.lang.reflect.Field.get(Field.java:358) at org.eclipse.persistence.internal.descriptors.InstanceVariableAttributeAccessor.getAttributeValueFromObject(InstanceVariableAttributeAccessor.java:76) ... 30 more
good stuff, although just to say that we cant really start caching the entities that are protected/isolated as it would increase the amount of locking exceptions and subsequent retrys by a fairly large amount with associated performance hit from db roundtrips - so we are looking for a fix at some point. I guess we could use QueryHints.REFRESH(_CASCADE) /em.refresh for all those entities when they are retrieved instead ? but that's probably not the best way forward for us... Cheers
I am working on a fix. The current target is our 2.2.1 release. I will update the bug if that changes.
Created attachment 199054 [details] proposed fix - 2.2 stream
Created attachment 199065 [details] proposed fix - trunk
Checked in change to trunk, 2.3.1 and 2.2.1 The change builds a data-holder-cache key to hold aggregates so they can be retrieved in the valueFromRow method when using protected caching. Reviewed by Gordon Yorke Tested with Core and JPA LRG Added test to CacheableModelJUnitTest
Cheers Tom , that appears to have fixed our problem too (nightly build 2.2.1.v20110705-r9664). Do you know when the next milestone/release for 2.2.1/2.3.1 are due - nothing obvious under http://www.eclipse.org/projects/project_summary.php?projectid=rt.eclipselink Tim
We have just started our work towards 2.2.1 and 2.3.1, so there are no official milestone dates yet. I just talked to our build engineer and we are planning on milestones for both by the end of next week.
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink