Community
Participate
Working Groups
org.eclipse.persistence.internal.descriptors.MethodAttributeAccessor getAttributeValueFromObject() can throw an additional NullPointerException when attempting to handle a NullPointerException upon invoking a configured method on a null object. org.eclipse.persistence.internal.descriptors.InstanceVariableAttributeAccessor getAttributeValueFromObject() does not have this issue, as it utilizes a null check in its exception handling code.
This error may occur when two parent objects are (incorrectly) referencing the same aggregate object. Resolving this issue will contribute to how diagnosable this potential problem is in the long run.
Created attachment 197547 [details] Proposed fix Proposed fix. Follows same pattern as the implementation of the same superclass method in InstanceVariableAttributeAccessor.
"reproduced" the incorrect scenario of sharing aggregate objects in EL trunk: Local Exception Stack: Exception [EclipseLink-69] (Eclipse Persistence Services - @VERSION@.@QUALIFIER@): org.eclipse.persistence.exceptions.DescriptorException Exception Description: A NullPointerException was thrown while extracting a value from the instance variable [endDate] in the object [null]. Internal Exception: java.lang.NullPointerException Mapping: org.eclipse.persistence.mappings.DirectToFieldMapping[endDate-->EMPLOYEE.END_DATE] Descriptor: RelationalDescriptor(examples.sessions.threetier.model.EmploymentPeriod --> [DatabaseTable(EMPLOYEE), DatabaseTable(SALARY)]) at org.eclipse.persistence.exceptions.DescriptorException.nullPointerWhileGettingValueThruInstanceVariableAccessor(DescriptorException.java:1263) at org.eclipse.persistence.internal.descriptors.InstanceVariableAttributeAccessor.getAttributeValueFromObject(InstanceVariableAttributeAccessor.java:88) at org.eclipse.persistence.mappings.DatabaseMapping.getAttributeValueFromObject(DatabaseMapping.java:516) at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.compareObjects(AbstractDirectMapping.java:455) at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.compareForChange(AbstractDirectMapping.java:407) at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.createObjectChangeSetThroughComparison(DeferredChangeDetectionPolicy.java:165) at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.createObjectChangeSet(DeferredChangeDetectionPolicy.java:137) at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.calculateChanges(DeferredChangeDetectionPolicy.java:89) at org.eclipse.persistence.internal.descriptors.ObjectBuilder.compareForChange(ObjectBuilder.java:1964) at org.eclipse.persistence.mappings.AggregateMapping.compareForChange(AggregateMapping.java:313) at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.createObjectChangeSetThroughComparison(DeferredChangeDetectionPolicy.java:165) at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.createObjectChangeSet(DeferredChangeDetectionPolicy.java:137) at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.calculateChanges(DeferredChangeDetectionPolicy.java:89) at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.calculateChangesForExistingObject(DeferredChangeDetectionPolicy.java:54) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.calculateChanges(UnitOfWorkImpl.java:636) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1482) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitRootUnitOfWork(UnitOfWorkImpl.java:1317) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commit(UnitOfWorkImpl.java:1079)
The following Employee demo-based example was used: UnitOfWork uow = getSession().acquireUnitOfWork(); Employee employee1Original = new Employee(); Employee employee2Original = new Employee(); Employee employee1Clone = (Employee) uow.registerObject(employee1Original); Employee employee2Clone = (Employee) uow.registerObject(employee2Original); employee1Clone.setMale(); employee1Clone.setFirstName("Joe"); employee1Clone.setLastName("Someone"); employee1Clone.setSalary(1234); employee1Clone.setPeriod(new EmploymentPeriod()); // not null employee2Clone.setFemale(); employee2Clone.setFirstName("Jill"); employee2Clone.setLastName("Someone"); employee2Clone.setSalary(1234); employee2Clone.setPeriod(null); // deliberately null uow.commit(); uow = getSession().acquireUnitOfWork(); employee1Clone = (Employee)uow.registerObject(employee1Original); // UoW backup clone's 'period' attribute is null employee2Clone = (Employee)uow.registerObject(employee2Original); employee2Clone.setPeriod(employee1Clone.getPeriod()); // 1. share the aggregate uow.commit();
Created attachment 198561 [details] Proposed fix
Aggregate sharing testcase no longer reproduces with the changes from: Revision: 9610 Author: gyorke Date: 2:47:23 PM, June 22, 2011 Message: Bug 300108 - Any changes that reference detached object will cause detached to be inserted I've attached the exception fix I was working on, for brevity. This exception would be thrown, instead of an NPE when the attribute accessor attempted to invoke on a null object.
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink