NPE in MethodAttributeAccessor.getAttributeValueFromObject [message #1720669] |
Wed, 20 January 2016 08:59 |
Ludwig Moser Messages: 476 Registered: July 2009 |
Senior Member |
|
|
i searched the forum and found some 'similar' exceptions but mine seems a bit different because mine gets raised when building the exception, whereat the others gain the build exception!
// Some JVM's throw this exception for some very odd reason
throw DescriptorException.nullPointerWhileGettingValueThruMethodAccessor(getGetMethodName(), anObject.getClass().getName(), exception);
in my case i get a NPE because anObject is null!
Caused by: java.lang.NullPointerException
at org.eclipse.persistence.internal.descriptors.MethodAttributeAccessor.getAttributeValueFromObject(MethodAttributeAccessor.java:92)
at org.eclipse.persistence.internal.descriptors.MethodAttributeAccessor.getAttributeValueFromObject(MethodAttributeAccessor.java:61)
at org.eclipse.persistence.mappings.DatabaseMapping.getAttributeValueFromObject(DatabaseMapping.java:630)
at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.compareObjects(AbstractDirectMapping.java:407)
at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.compareForChange(AbstractDirectMapping.java:381)
at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.createObjectChangeSetThroughComparison(DeferredChangeDetectionPolicy.java:186)
at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.createObjectChangeSet(DeferredChangeDetectionPolicy.java:146)
at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.calculateChanges(DeferredChangeDetectionPolicy.java:91)
at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.calculateChangesForExistingObject(DeferredChangeDetectionPolicy.java:56)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.calculateChanges(UnitOfWorkImpl.java:664)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1516)
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:277)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1169)
at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:132)
i can reproduce this step with ONE of my generic Classes that i pass to my generic save() method. I can't see the difference from this Class to all others i created, but as the objectInstance is null itself i doubt its a problem from my api.
(i create a save() method on my class, which passes this to my persistence service by doing something like this (pseudocode)
MyClass.save() {
Persistence.save(this);
}
so by doing it this way, the object to be saved cannot be null...
when stepping through the stack it seems that EL thinks the object to be saved is already in db, but actually it is not!
why i do think so? because in (AbstractDirectMapping) th NPE hits the line marked /**/
@Override
public ChangeRecord compareForChange(Object clone, Object backUp, ObjectChangeSet owner, AbstractSession session) {
// same code as write from object into row for update
if (owner.isNew()) {
return internalBuildChangeRecord(getAttributeValueFromObject(clone), null, owner);
/*-->*/ } else if (!compareObjects(backUp, clone, session)) {/**/
Object oldValue = null;
if (backUp != null && clone != backUp) {
oldValue = getAttributeValueFromObject(backUp);
}
return internalBuildChangeRecord(getAttributeValueFromObject(clone), oldValue, owner);
}
return null;
}
how can i get rid of this (or create a workaround)?
EDIT: i'm using EL 2.6.1
[Updated on: Wed, 20 January 2016 10:22] Report message to a moderator
|
|
|
|
Re: NPE in MethodAttributeAccessor.getAttributeValueFromObject [message #1720799 is a reply to message #1720748] |
Thu, 21 January 2016 07:01 |
Ludwig Moser Messages: 476 Registered: July 2009 |
Senior Member |
|
|
hi Chris,
My Framework uses EMF, so all my objects extend EObject instead of Object (but this should not be a problem at all)
all i do to my object-to-be-saved:
create a new Instance.
set some values (probably assign some references to other objects, which are already in the database)
save()
so at this time there are no ("active") relations to the class active. relations to other classes/objects should not be a problem.
every Class extends GUID, which got an Id and an Guid.
my Class GUID has this method:
public EObject save() {
return Services.get(StorageService.class).getPersistenceService().internalSave(this);
}
this retrieves an osgi service 'StorageService' which holds a PersistenceService (in this case EclipseLink)
the PersistenceService provides the internalSave(GUID item) method.
my internalSave method might look odd (superhuge) but actually its just loads of logging and exception handling. the actual code is pretty simple.
Check if the item was changed or not.
if it was not changed -> return; (note changed does not depend on if it was stored in db yet, just means it was modified from default values in the application)
if it was changed we have two possibilities:
new -> insert
pop up an dialog and show the user which values were changed. let him decide if he wants to save or not.
iff (yes=>save), otherwise refresh the item from database.
not new -> update:
for both, save and update, some administrated fields are written programmatically (i do not want this as triggers in database for some reasons! - i had them in db before) - this should not be a problem either!
note: transient decides if the item gets discarded (my table automatically triggers the save() method when it looses focus in my table, if transient then no save and removed from table.)
PersistenceService.internalsSave(item):
private <E extends GUID> E internalSave(E item) {
if (debug)
System.out.println("internalSave");
boolean wasTransient = item.isTransient();
GUID guidItem = (GUID) item;
if (!guidItem.isChanged()) {
if (debug)
System.out.println("item [" + item.getClass().getSimpleName() + "] has no changes -> dont try to save");
return item;
} else {
if (debug)
System.out.println("item [" + item.getClass().getSimpleName() + "] has changes -> try to save");
// there was a change, so check settings what to do now
// open dialog
DialogService ds = Services.get(DialogService.class);
Map<String, Object> params = new HashMap<String, Object>();
params.put("title", Locale.AutoSaveDialog_title);
String message = String.format("%s\n\t%s", Locale.AutoSaveDialog_message,
Lists.toUIString(item.getChanges()));
params.put("message", message);// Locale.AutoSaveDialog_message);
Boolean doSave = (Boolean) ds.openDialog(DialogEnum.AUTOSAVE, params);
// user dediced not to save and item is not transient
if (!doSave && !item.isTransient()) {
System.out.println("user has chosen not to save -> load original values from DB");
// load old data into DS and abort!
EntityManager em = getEntityManager();
em.refresh(item);
item.setUnchanged();
return item;
}
}
EntityManager em = getEntityManager();
boolean failed = false;
try {
E newItem;
// no id -> new
if (item.getId() == null) {
if (debug)
System.out.println("\tINSERT");
// insert
try {
// fill admin stuff
if (item instanceof Administrated) {
Administrated admin = (Administrated) item;
admin.setAdminCreator(Utils.getUserDomainName());
admin.setAdminCreated((Calendar) Calendar.getInstance().clone());
admin.setAdminEditor(Utils.getUserDomainName());
admin.setAdminEdited((Calendar) Calendar.getInstance().clone());
}
em.getTransaction().begin();
if (debug)
System.out.println("TRYING TO PERSIST");
em.persist(item);
try {
em.getTransaction().commit(); // 1
item.setUnchanged();
item.setTransient(false); // saved!
System.out.println("(insert-success) changed -> false");
System.out.println("\twasTransient: " + wasTransient);
System.out.println("\tisTransient: " + item.isTransient());
} catch (Exception e) {
System.out.println("swallowed an em.getTransaction().commit() Exception");
System.out.println("code# " + ExceptionUtil.getErrorCode(e));
e.printStackTrace();
System.out.println("###---###---###");
if (e instanceof DatabaseException) {
DatabaseException dex = (DatabaseException) e;
System.out.println("Database Error Code# " + dex.getDatabaseErrorCode());
System.out.println("Error Code# " + dex.getErrorCode());
int errCode = dex.getDatabaseErrorCode() != 0 ? dex.getDatabaseErrorCode()
: dex.getErrorCode();
System.out.println("final Error Code# " + errCode);
}
if (e instanceof javax.persistence.RollbackException) {
e = (Exception) e.getCause();
while (e != null) {
System.out.println("Message : " + e.getMessage());
System.out.println("Caused by: " + e);
e = (Exception) e.getCause();
}
}
//
item.setTransient(true); // save failed -> discard
System.out.println("(insert-fail) changed -> false");
System.out.println("\twasTransient: " + wasTransient);
System.out.println("\tisTransient: " + item.isTransient());
item.save(); // retry - this worked for some very odd reasons (not anymore)
}
System.out.println("\tsuccess.");
return item;
} catch (Exception e2) {
System.out.println("\tfailed -> rollback");
if (em.getTransaction().isActive()) {
try {
em.getTransaction().rollback();
} catch (RuntimeException e) {
// Log rollback failure or something
}
}
System.out.println("exception while PERSIST (" + e2.getClass().getSimpleName() + ") "
+ System.currentTimeMillis());
Throwable t = null;
for (t = e2.getCause(); t.getCause() != null; t = t.getCause())
;
// casting Throwable object to SQL Exception
SQLException sqlex = (SQLException) t;
item.setTransient(true); // save failed -> discard
System.out.println("(rollback) changed -> true");
System.out.println("\twasTransient: " + wasTransient);
System.out.println("\tisTransient: " + item.isTransient());
}
} else {
// update
System.out.println("UPDATE");
if (debug) {
System.out.println("updating");
System.out.println("item.isChanged() -> " + item.isChanged());
}
try {
if (item instanceof Administrated && item.isChanged()) {
if (debug)
System.out.println("item has changed -> update Admin Fields: " + item);
Administrated admin = (Administrated) item;
admin.setAdminEditor(Utils.getUserDomainName());
admin.setAdminEdited((Calendar) Calendar.getInstance().clone());
}
em.getTransaction().begin();
if (debug)
System.out.println("TRYING TO MERGE");
EList<PropertyChangeListener> listeners = item.getListeners();
item.clearListeners();
if (debug)
System.out.println("<pre>" + item);
newItem = em.merge(item);
if (debug)
System.out.println("<post>" + newItem);
for (int i = 0; i < listeners.size(); i++) {
newItem.addPropertyChangeListener(listeners.get(i));
}
if (debug)
System.out.println("MERGE Finished");
if (!newItem.equals(item)) {
// replace it in controller, List and Current
Services.getController().replace(item, newItem); // replace the old Item with the newItem
}
em.getTransaction().commit();
item.setUnchanged();
item.setTransient(false); // discard the old one
System.out.println("(update) changed -> false");
System.out.println("\twasTransient: " + wasTransient);
System.out.println("\tisTransient: " + item.isTransient());
System.out.println("\tsuccess");
} catch (Exception e) {
System.out.println("\tfailed.");
System.out.println("catch (Exception e)");
if (em.getTransaction().isActive()) {
try {
em.getTransaction().rollback();
} catch (RuntimeException ex) {
// Log rollback failure or something
}
}
System.out.println("exception while MERGE (" + e.getClass().getSimpleName() + ") "
+ System.currentTimeMillis());
while (e.getCause() != null) {
e = (Exception) e.getCause();
}
if (e instanceof NullPointerException) {
System.out.println("### reSave");
// this is from original EclipseLink-Source:
// Some JVM's throw this exception for some very odd reason
item = (E) item.save();
return item;
}
String message = e.getMessage();
if (message == null) {
message = "no message";
}
System.err.println("Merging failed - Should never happen though");
// mark as unsaved if no id is available...
if (item.getId() == null) {
item.setTransient(true); // discard
System.out.println("(update-fail) changed -> true");
System.out.println("\twasTransient: " + wasTransient);
System.out.println("\tisTransient: " + item.isTransient());
}
}
}
} catch (PersistenceException ex) {
failed = true;
Throwable t = null;
for (t = ex.getCause(); t.getCause() != null; t = t.getCause())
;
System.err.println(Locale.SaveError);
System.err.println("MESSAGE:_" + t.getMessage());
SQLException sqlex = (SQLException) t; // casting Throwable object
// to SQL Exception
if (debug) {
System.out.println("SQLException: ");
System.out.println("SQLState: " + sqlex.getSQLState());
System.out.println("ErrorCode: " + sqlex.getErrorCode());
System.out.println("msg: " + sqlex.getMessage());
System.out.println("loc msg: " + sqlex.getLocalizedMessage());
}
item.setTransient(true);
System.out.println("(update-fail-fail?) changed -> true");
System.out.println("\twasTransient: " + wasTransient);
System.out.println("\tisTransient: " + item.isTransient());
}
if (debug) {
if (!failed)
System.out.println("persisted item: " + item);
if (failed)
System.out.println("item not persisted: " + item);
}
return item;
}
waiting for your reply - thanks!
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.03262 seconds