Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » NPE in MethodAttributeAccessor.getAttributeValueFromObject
NPE in MethodAttributeAccessor.getAttributeValueFromObject [message #1720669] Wed, 20 January 2016 08:59 Go to next message
Ludwig Moser is currently offline Ludwig MoserFriend
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 #1720748 is a reply to message #1720669] Wed, 20 January 2016 16:03 Go to previous messageGo to next message
Chris Delahunt is currently offline Chris DelahuntFriend
Messages: 1389
Registered: July 2009
Senior Member
There is more required to be able to determine what might be causing the issue. Are you doing anything with this entity elsewhere - such as dereferencing it from a relationship marked with the orphan removal set to true? What does the Persistence.save(this) actually do? Are you using flush somewhere after you persist/merge?

The NPE is caused because it is finding a null in its list of registered/managed objects. The problem won't be in the commit call itself, but well before that - at first glance it seems related to https://bugs.eclipse.org/bugs/show_bug.cgi?id=457480. Checking out the fix for that bug, I suspect it is the same problem and the fix is just too narrow, but I would need to see your entity to tell if it is similar to the situation described in the bug.
Re: NPE in MethodAttributeAccessor.getAttributeValueFromObject [message #1720799 is a reply to message #1720748] Thu, 21 January 2016 07:01 Go to previous messageGo to next message
Ludwig Moser is currently offline Ludwig MoserFriend
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!
Re: NPE in MethodAttributeAccessor.getAttributeValueFromObject [message #1721196 is a reply to message #1720799] Mon, 25 January 2016 15:47 Go to previous messageGo to next message
Chris Delahunt is currently offline Chris DelahuntFriend
Messages: 1389
Registered: July 2009
Senior Member
Sorry, your internalSave method is a bit long to really step through and understand what might be happening during this issue. I'd suggest you break it down into a small test case that reproduces it - you'll need to anyway if this is a bug. Check out the entity you are saving and see if it is similar to the one in the test case at https://bugs.eclipse.org/bugs/show_bug.cgi?id=457480 as I suspect you are hitting that bug, just at a different spot. If you can verify that it is a similar model and have a test case, reopen the EL bug and file an Oracle bug if you have a support contract.

Best Regards,
Chris
Re: NPE in MethodAttributeAccessor.getAttributeValueFromObject [message #1721198 is a reply to message #1721196] Mon, 25 January 2016 15:54 Go to previous messageGo to next message
Ludwig Moser is currently offline Ludwig MoserFriend
Messages: 476
Registered: July 2009
Senior Member
i do not create no relations on the new object. so the problem causing bug 457480 appears different to me.

i tested more now. and noticed that this problem only occurs on FIRST attempt!
if i create another instance of my Class, all is working as expected. Very strange!

the problem would be solved withing 5s if there would be seperate methods for update and insert...
the fact that the persist method handles both it more complex for me (and raises this problem)

i doubt that i can extract the problem, as my whole model is 26 classes and i only get the problem on one of em (with loads of attributes) and with this only on first try.
BUT i'll try to do so. keep you updated if something changes!
Re: NPE in MethodAttributeAccessor.getAttributeValueFromObject [message #1721335 is a reply to message #1721198] Tue, 26 January 2016 16:31 Go to previous message
Ludwig Moser is currently offline Ludwig MoserFriend
Messages: 476
Registered: July 2009
Senior Member
UPDATE: its not a nice solution, but it works.
if the save() fails, i just call save() again, and on second save it works.

its a brute force workaround - far from what i call perfect or good coding style, but it seems the only way to get around this bug. (i was not able to reproduce the bug in a simple commandline application...)
Previous Topic:Is Eclipse Dynamic Persistence support SINGLE_TABLE Inheritance strategy ?
Next Topic:EclipseLink on Android?
Goto Forum:
  


Current Time: Fri Mar 29 14:38:49 GMT 2024

Powered by FUDForum. Page generated in 0.03262 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top