|
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-02-04 06:41:14
|
>In response to the "Lazy Initialization of Objects" request, some comments: >Not trivial. Approaches that I know of: >- pre/post processing to insert code that manages this >- use of interfaces and proxies >- provide an API and let the coder do it. Unfortunately, there is no way to do this in Java that is extremely compatible with the philosophy of Hibernate (ie. use dynamic techniques as much as possible but minimize model intrusion) There are straightformard approaches in more dynamic languages like SmallTalk, Python et al. If Java would have let you create a java.lang.Proxy from a class, instead of only from interfaces, it would be much easier. My preferred technique is this: 1. Let the developer build the system without lazy instantiation 2. At deployment time have a tool to generate proxy classes that inherit the business classes and override every public, package and protected method with a method that calls the initialization code when needed (and then invokes super). This implies source generation which is quite easy to do using reflection. 3. At runtime, the persistence layer can check for the existence of a proxy class (using a naming convention), if it exists, return that to the application, otherwise return an initialized instance. This has following advantages: 1. The only model intrusion is you cant use final classes or methods if you want lazy initialization. That fine; you can still have one or the other on a class by class basis. 2. No code-generation required during the test/debug cycle. 3. You can choose which classes are initialized lazily at deployment time, simply by choosing which proxies to deploy. 4. No mutilation of sourcecode - so line-numbers, etc stay intact in stacktraces. 5. No extra proxy objects floating around wasting memory. 6. No use of reflection _inside_ the application code. (A reflective solution here could actually be a performance hurdle if proxies get invoked inside a loop.) Does anyone see any major disadvantages of this solution? |
|
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-02-04 10:42:34
|
Actually instanceof will still work. For example:
class Foo implements Persistent {
String name;
String id;
String getName() {..}
void setName(String name) { ...}
String getID() { ....}
void setID(String id) { .... }
......
}
Foo has the proxy subclass FooProx (not strictly a proxy cos its not really
using delegation)
FooProx extends Foo {
String getName() { ....; return super.getName(); }
void setName(String name) { ...; super.setName(name) }
String getID() { ....; return super.getID(); }
void setID(String id) { ....; super.setID(id); }
}
so an instance of FooProx is also an instance of Foo. So instanceof works
fine. also Foo.class.isAssignableFrom( foo.getClass() ) works.
foo.getClass().isAssignableFrom( Foo.class ) breaks but i think thats the
less important case. Actually def less important.
reflection still works .... you will get a different bunch of methods but
they do the right thing.....
foo.getClass()==Foo.class breaks ... thats kind of nasty ... could break
equals(). But then the proxies might even be smart enough to do something
special in the case of equals.
foo.getClass.getName() breaks...
notify(), wait() and synchronized() all work (they wouldnt if you were
using seperate wrapper objects.
most importantly == works which it wouldn't if you use seperate wrapper
objects that delegate.
Actually the reason all this is okay is because we are using polymorphism
which is fundamentally OO. So basically the only real problem is getClass()
and that only because its declared final on Object.
|
|
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-02-04 13:30:15
|
sorry... reading your email again I realise your point is more that things
like
foo.getClass().isAssignableFrom( bar.getClass() )
and
foo.getClass().isInstance(bar)
wont work ( where Bar inherits Foo ) but note that bar instanceof Foo still
works which is way more important.
I missed the little prime (') ....
Still I think if you are doing things like the above in your business model
code, you are probably doing something wrong. Such things should be rare
and where they _are_ used you can always just not use lazy init. I guess
theres still a worry about other tools that use reflection ......
Obviously bytecode processing is a more powerful technique for this
particular problem but also a *much* more difficult one to get right
(anyone wanna debug that stuff? Or read stack traces?)
Arguably, lazy instantiation of direct references is *much* less important
than lazy instantiation of collections anyway, so I wouldn't want to expend
too much effort upon this problem.
Gavin
|
|
From: Paul S. <pau...@ne...> - 2002-02-04 10:00:13
|
Gavin_King/Cirrus%CI...@ci... wrote: > > My preferred technique is this: > 1. Let the developer build the system without lazy instantiation > 2. At deployment time have a tool to generate proxy classes that inherit > the business classes and override every public, package and protected > method with a method that calls the initialization code when needed (and > then invokes super). This implies source generation which is quite easy to > do using reflection. > 3. At runtime, the persistence layer can check for the existence of a proxy > class (using a naming convention), if it exists, return that to the > application, otherwise return an initialized instance. > > This has following advantages: > 1. The only model intrusion is you cant use final classes or methods if you > want lazy initialization. That fine; you can still have one or the other on > a class by class basis. > 2. No code-generation required during the test/debug cycle. > 3. You can choose which classes are initialized lazily at deployment time, > simply by choosing which proxies to deploy. > 4. No mutilation of sourcecode - so line-numbers, etc stay intact in > stacktraces. > 5. No extra proxy objects floating around wasting memory. > 6. No use of reflection _inside_ the application code. (A reflective > solution here could actually be a performance hurdle if proxies get invoked > inside a loop.) > > Does anyone see any major disadvantages of this solution? The derived class worries me a little - I don't think that messing with the class hierarchy is that nice. In fact I think it's pretty dangerous. For example, given B inherits from A where both are persistent (non-abstract). If we create an A' this is no longer an ancestor of B. I can think of lots of other cases that wouldn't work so well either, e.g. instanceof, isAssiganbleFrom() for starters. Not being final bothers me slightly, but not as much as messing with the class hierarchy. The only post-processor I've seen work actually mangled the bytecode, inserting the necessary code into relevant methods (usually get/set methods). Regards, PaulS :) |