I think this is a very worthwhile project. James and a few others
excoriated me about this issue over beers after JavaOne last week,
and, while the bruises from their rhetorical assault are still
healing, their observations about the comparative "out of the box"
ease of use OpenJPA compared to other systems definitely bears
attention.
As Patrick mentioned, we aren't too far away from being able to use a
dynamic subclassing approach.
Another option I've been thinking about recently is that in JDK 1.6,
you can dynamically attach an agent at runtime to your own JVM (using
an implementation-specific mechanism), and using the provided
Instrumentation, you can redefine existing methods in classes, even
after the classes have already been loaded. While you cannot add or
remove methods or fields, we might be able to re-work our PCEnhancer
to use a newly-generated inner class and a lookup in some
IdentityHashMap to perform the same function. E.g., instead of our
currently enhanced class:
public class SomeEntity {
private String someField;
private StateManager stateManager; // generated
public String getSomeField() {
return pcgetSomeField(this);
}
// generated method
private static String getSomeField(SomeEntity entity) {
if (entity.stateManager == null)
return entity.someField;
else
entity.stateManager.getField(1, entity);
}
}
we would instead do something like:
public class SomeEntity {
private String someField;
public String getSomeField() {
return GeneratedInnerClass.pcgetSomeField(this);
}
private static class GeneratedInnerClass {
private static String getSomeField(SomeEntity entity) {
StateManager stateManager = GlobalIdentityMap.get(entity);
if (stateManager == null)
return entity.someField;
else
stateManager.getField(1, entity);
}
}
}
From the brief amount of time I've spent thinking about this, I
think we can get 99% of the way there with our current approach.
The remaining 1% is a situation where if someone creates an instance
of SomeEntity *before* we ever initialize the BrokerFactory (and thus
perform the re-definition of known entity classes), we might get
passed an entity instance that isn't persist-able (since you cannot
redfine the methods for an already-created object, only for objects
that will subsequently be created).
In summary, we have 3 different possibilities for removing the
requirement for build-time enhancement and launch-time agent
specification:
1. Use reflection: considerably slower, would require drastic rework
of all our interaction with PersistenceCapable instances, but
wouldn't require any fancy class-generation/enhancement
2. Dynamic subclassing: easier to implement, but would require people
to use property accessors for everything, and wouldn't support
EntityManager.persist(someInstance)
3. Dynamic agent attachment and class re-definition: more difficult
to implement than #2, and would require JDK 1.6 + JVM implementation-
dependent attachment mechanisms, but might provide the most
functionality
Does anyone have any thoughts about this? Especially any new ideas
for other ways to do this would be very interesting for all of us to
hear.
On May 17, 2007, at 8:19 AM, Patrick Linskey wrote:
How hard is it to add a reflection/cglib type alternative to the
upfront
bytecode generation (like hibernate does) to save us from the
development-time pain?
Not particularly hard. There are a few APIs that would break for some
cases, but it's even pretty straightforward to do a subclassing
approach for property-based access type without losing much
performance -- the only cost in that configuration is with
persistent-new instances.
-Patrick
On 5/17/07, James.Strachan <[EMAIL PROTECTED]> wrote:
Firstly before I start, openjpa is a great piece of software; I'm
particularly fond of the documentation and in particular the query
language
parts. The CSS for the site is also awesome :)
However compared to hibernate, openjpa is still pretty painful to
use from
an end users perspective and I don't think this should be the
case; plus I
don't think it'll take much time to fix. While the pain is still
fresh in my
mind I thought I'd post on how much more painful openjpa is to use
in a
project. If you're short on time, the basic idea is its that
bytecode post
processing stuff thats to blame :). Yes I know its probably faster
that way
- its just so painful for Java programmers to work with. (And yes
I know one
day we'll all have IDE plugins that hide the bytecode stuff etc etc).
So the first thing is having to mess with your build (ant or
maven) to get
the post processing properly integrated. Depending on if you have
persistent
entities in your main or test area this can often trip you up a
little (as
it did me). I don't know about folks on this list but the whole
idea of
having to mess with my maven build gives me the jitters :). When
you get
that far & the maven planets are aligned with openjpa, the next
hurdle you
hit is how do you run stuff in your IDE. If like me you use IDEA
and maven
2, the project gets auto-created by default for all projects you
work on.
However these don't work when you use openjpa as you hit the
dreaded 'cannot
function at all as you've not run the up front bytecode post
processor you
dummy!' type error when trying to run stuff in your IDE.
So you then add the maven-generated classes to the front of the
classpath in
your project. Hooray, after a day or two's work, you can now
actually use
openjpa in your IDE and your build. YAY! The downside is that now
when
navigating around your Java code, whenever you navigate into an
entity bean,
IDEA shows you the bytecode - not the source code as its confused
since the
bytecode generated stuff is different to the source code it knows
about. So
now you're faced with a dilemma - choose between navigating nicely
around
your source code - or being able to actually run/debug your
application. I
won't even get into the refactoring pain or having to continuously
run maven
builds while developing code to avoid getting code completion/
compile errors
etc. (I prefer to keep in my IDE where possible).
Compare this whole malarkey with hibernate. You add hibernate to
your pom,
generate your project and you're good to go. No messing with your
project
build; no messing with some secret ninja IDE stuff to be able to
actually
run & debug your code while still being able to actually navigate the
source. It just works. Now it might work in a crappy & slow way
and openjpa
might be way way more efficient and powerful and whatnot - but I'd
rather
have a cheap car that just works than a ferrari that you can only
drive on a
tuesday if its sunny, but not too hot and refuses to even start if
its wet.
FWIW I've just given up using openjpa for development; its just
way too
painful. (I'm even hacking projects I work on so I use openjpa in
the maven
build but explicitly switch to hibernate in development mode; yeah
its more
work but at least I can use my IDE properly again).
I'm cool with putting post processing into the build system
(though that
should really only be an optimisation); but please can we have some
inefficient but usable reflection/cglib type approach so folks can
easily
switch from hibernate to openjpa (and stay there) without pulling
out our
hair & swearing too much - or sneaking back at the first
opportunity to get
an easy life?
Please don't take this mail the wrong way - I truly want openjpa
to be a
success, its a great piece of software. Its just a bit too hard to
use out
of the box right now. I'd truly like it to be trivial to switch from
hibernate to openjpa and never have to go back.
How hard is it to add a reflection/cglib type alternative to the
upfront
bytecode generation (like hibernate does) to save us from the
development-time pain?
--
James
-------
http://macstrac.blogspot.com/
--
View this message in context: http://www.nabble.com/the-pain-of-
post-processing-bytecode-%28another-beg-for-a-simple-reflection-
cglib-alternative-like-hibernate%29-tf3770760.html#a10660986
Sent from the open-jpa-dev mailing list archive at Nabble.com.
--
Patrick Linskey
202 669 5907