Reputation: 24114
In my app I'm connected to a websocket. The socket is sending JSON data. As it is becoming available I process it in a different Job. In each job, I convert the JSON to a model object with GSON. There are 3 types of models, all independent, and with one common timestamp field in a MappedSuperclass. They don't have an id explicit field. I call save on the model and in 1 out of 1000 times a "PersistentObjectException: detached entity passed to persist" is thrown.
The multiple jobs are called from a start up Job that connects to the websocket. The library I'm using creates a different thread for each incoming message. I then convert the thread into a job before saving to the database. I do this, because otherwise another PersistentObjectException is thrown about changing the id from 1 to 2 or something similar, if I allow the original thread to call save.
I also have another job running that accesses the database at the same time. What could be wrong?
@Override
public void onMessage(final WebSocketMessage message){
new Job() {
@Override
public void doJob() {
processMessage(message.getText());
}
}.now();
}
public void processMessage(String message) {
Appointment appointment = new Gson().fromJson(message, Appointment.class);
appointment.save();
}
@Entity
public class Appointment extends CalendarEvent {
private String owner;
}
@MappedSuperclass
public abstract class CalendarEvent extends Model {
private long timestamp;
}
EDIT: Added some code sample
Upvotes: 3
Views: 11079
Reputation: 24114
I've found this workaround to work for now. Maybe it's to do with how Gson and Jpa interact. Not sure...
public void processMessage(String message) {
Appointment appointment = new Gson().fromJson(message, Appointment.class);
//recreate appointment
appointment = new Appointment(appointment);
appointment.save(); }
Upvotes: 0
Reputation: 10007
Basically it means the EntityManager
won't track them any more: This is a good overview. How they come to be considered detached when you didn't explicitly ask for it is odd. But the workaround might be to use a "defensive" approach in your DAO method and merge
these odd cases; i.e.:
public void save (Model possiblyDetachedModel) {
if (entityManager.contains(possiblyDetachedModel)) {
entityManager.merge(possiblyDetachedModel);
} else {
entityManager.persist(possiblyDetachedModel);
}
}
I don't particularly like it, because it shouldn't need to be done when you're persist
ing brand-new objects. It might be worth putting some logging in (or debugging if at all possible) the "merge
" branch and really inspecting those rogue objects - I'm pretty sure the EntityManager
can only use the @Id
field as the detection mechanism...
Upvotes: 5