Reputation: 62789
I would like to implement a ORM-style system that can save updates to POJOs when they are no longer reachable by the caller.
I thought the reference classes could do it, but they seem to only enqueue the reference after the object has been cleared (I was hoping it was when they were able to be collected), so once enqueued the .get() method will always return null.
I could use a finalizer but last time I checked those were questionable (Not guaranteed to run promptly or run at all)--I believe a combination of finalizers and runShutdownHook() would work but that's getting into fairly swampy territory.
Is there another path I'm not thinking besides the obligatory "Just have the caller call .save() when he's done"?
Upvotes: 0
Views: 321
Reputation: 46476
Are you just trying to avoid having to call save()
on every POJO that you modify?
This can be done reliably using a persistence session object, like this:
And if you don't want to pass session objects through your code, you can take things a step further with the Unit of Work pattern, associating a session object to the current thread:
This fixes several problems with a reachability based solution:
Perhaps see http://nhibernate.info/doc/patternsandpractices/nhibernate-and-the-unit-of-work-pattern.html or research the Unit of Work pattern and emulate some of those ideas.
Upvotes: 1
Reputation: 719386
I think you are barking up the wrong tree here.
All of Java's finalizer and Reference mechanisms based on reachability depend on the garbage collector to determine whether the respective objects are reachable. So if you use any of the Reference mechanisms for some kind of finalization, you run into much the same issues that make finalize
a bad idea.
It is technically possible to implement your own mechanisms for doing reachability; e.g. by implementing your own application-specific reference counting. However, it is likely to be expensive, fragile, and make your code look horrible. (Reference counting in Java is likely to be messier and more fragile than in C++, because you can't overload reference assignment operators to ensure that reference counts are adjusted transparently. So every reference assignment needs to be wrapped in a method call.) So I'd say that doing your own reachability analysis is a bad idea.
So, to be practical you need to either:
The first option is clearly the best, IMO.
Upvotes: 1
Reputation: 45453
maybe you can subclass PhantomReference, and store necessary data in it for final actions.
Upvotes: 0
Reputation: 3056
Use the Observer Pattern do build a ClearanceManager and some Destroyables. IDestroyable is an interface, which is used for the observers it contains the method public void destroy() The ClearanceManager is the Subject of the Observerpattern. Maybe use Singleton here to ensure you have just one ClearanceManager object in your application.
Use a Set internaly inside the ClearanceManager (not a List to ensure Objects can just be added once)
support an addDestroyable(IDestroyable destoryable) method (and maybe a removeDestroyable one).
During Runtime the Classes for which you need some destructor emulation, can register them self at the ClearenceManager. ClearenceManager.getInstance().addDestroyable(this);
The ClearanceManager has an doClearance() method, which should just be called at the end of the Main method. It iterates threw the private Set and calls destroy() on every IDestroyable object.
Doing it this way you can emulate destructors, without using them, because using destructors you are losing control about the existance of myabe needed object. You do not know when overwriting finalize, when it is called.
Maybe, if you do not want to call doClearance() in your Main method you can use here, but just here, a real destructor finalize(). Because there are references in the ClearenceManager to the needed Objects, they will not be destroyed first. But maybe mhh, if there are cross references .... better do not use finalize, use doClearance() and have fun with it :)
Upvotes: 1