I'm experimenting with the new JPA APIs by writing some simple
CRUD-based examples. Add, update, and display all work great ... but
I'm running into an exception (documented below) when trying to remove a
detail row. I am using Glassfish Build 48, and building the test code
with NB 5.5 beta.
I've got two entity classes that, among other things, have a
bidirectional one-to-many relationship with each other:
@Entity
public class User implements Serializable {
....
@OneToMany(mappedBy="user")
private List<Subscription> subscriptions;
...
public List<Subscription> getSubscriptions() { return
this.subscriptions; }
public void setSubscriptions(List<Subscription> subscriptions) {
this.subscriptions = subscriptions;
}
...
}
@Entity
public class Subscription implements Serializable {
...
@ManyToOne
private User user;
...
public User getUser() { return this.user; }
public void setUser(User user) { this.user = user; }
...
}
Note that the above classes correctly implement hashCode() and equals()
as well ... without that the comparisons performed would be failing.
According to the JPA specification, it is the application's
responsibility to maintain the properties that implement the
relationship, so I've added a convenience method to the User class like
this:
public void removeSubscription(Subscription subscription) {
if ((subscriptoin == null) || (subscriptions == null)) {
return;
}
if (subscriptions.contains(subscription)) {
subscriptions.remove(subscription);
subscription.setUser(null);
}
}
Now, my business logic looks like this:
@PersistenceContext
EntityManager em; // Injected for me
@Resource
UserTransaction utx; // Injected for me
Subscription subscription = ...; // A detached copy of a
Subscription entity
// Start a transaction
utx.begin();
// Merge the detached entity back in
em.merge(subscription);
// Attempt to remove the subscription
subscription.getUser().removeSubscription(subscription);
// Remove the subscription from the database too
em.remove(subscription);
// Complete the transaction
utx.commit();
However, I get an exception from TopLink Essentials that looks like this:
java.lang.NullPointerException
at
oracle.toplink.essentials.internal.indirection.UnitOfWorkValueHolder.instantiate(UnitOfWorkValueHolder.java:217)
at
oracle.toplink.essentials.internal.indirection.DatabaseValueHolder.getValue(DatabaseValueHolder.java:82)
at
oracle.toplink.essentials.indirection.IndirectList.buildDelegate(IndirectList.java:193)
at
oracle.toplink.essentials.indirection.IndirectList.getDelegate(IndirectList.java:315)
at
oracle.toplink.essentials.indirection.IndirectList.contains(IndirectList.java:249)
at myjpaexample.User.removeSubscription(User.java:99)
where line 99 in User is the line inside removeSubscription() that calls
"subscriptions.contains()". Various attempts to remove the subscription
from the list by other means all seem to end up with an NPE at the same
place.
Any ideas?
Craig McClanahan