openjpa-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From atanamir <step...@hyarros.com>
Subject Re: Generics Support
Date Sun, 16 May 2010 09:56:28 GMT

Hi Kevin/Other devs,

Thanks for the reply and encouragement.  I've been investigating / figuring
out the OpenJPA code for the past few days, and it seems it'll require a
rather significant overhaul of the Metadata-related classes for this to work
right, in addition to the way the metadata code is called from other sites. 
I'll try to describe the basic work that needs to be done here, and
hopefully you guys can help me determine the right place to start (since
there's a lot of code, hopefully someone more experienced can give me some
pointer on exactly where to begin).  

*** QUICK INTRO TO GENERICS REFLECTION *** 

Given the following class structure:

class Base<T> { T field; } 
class A extends Base<Something> { ... }
class B extends Base<AnotherThing> { ... }
class C extends Base<SomethingFancy<BlahBlah> > { ... }
class D extends A { ... }

Reflection will return Base<T> as the Class for getSuperclass() when called
on an instance of any of A, B, or C (as expected).  All of the Class
instance representing the Base<T> is equal() for instances of A, B, and C. 
Furthermore, there will be no type argument information in the Class
instance for Base<T>.  This information is kept in the class instance for A,
B, and C itself, and can be accessed using getGenericSuperclass().  When the
field 'field' is accessed in any of the derived classes, reflection will
simply return java.lang.Object for the type of the field with standard APIs. 
There's nothing to hint that it's acutally a generic -- this is because of
Java's type erasure.  An additional API call, getGenericType() will let you
know the type of the field is acutally a TypeVariable.  The resolution of
this Type Variable to a concrete class must be done at the level of derived
classes, matching up the TypeVariable with the supplied actual type
arguments.  

In the case of class D, which extends A, getting the type of field 'field'
is still going to be java.lang.Object.  One must acutally traverse up into A
to get the type arguments, and traverse up again into Base to determine that
Base is the container for field 'field'.  

So we'll need a nice chunk of logic to resolve type variables and match them
up with the type arguments, since they can be separated by large distances
in the type hierarchy, e.g.:

class A<T> { T x; } 
class B<T> extends A<T> { ... }
class C extends B<SomeClass> { ... }
class D  extends C { ... }
class E extends D<AnotherClass> { ... } <-- try to resolve the type of 'x'
from here!

*** END JAVA API TALK ***

*** START OpenJPA CODE TALK ***

Given the scenario described above, it's quite troublesome in OpenJPA right
now.  A class is parsed from bottom up, recursively.  If E is being parsed,
it will first parse the superclasses and construct their metadata before
continuing with E itself.  The problem is, the construction of the
superclass' field metadata will require E itself to figure out the type
arguments (or just classes farther down in the hierarchy).  Passing the
whole class tree along with the metadata construction calls seems kind of
clumsy.  That's the first problem to figure out.

Secondly, is the accessing of the 'type' of a field.  Because a superclass
will only have *one* ClassMetaData instance, every time one of the members
are accessed in that class, a subclass may need to be passed in for
context/resolution purposes.  If I have the class list:

class Base<T> { @Id T getId(); void setId(T id); }
class B extends Base<Integer> { ... }

I'll need to let the metadata for Base know that I'm working within the
context of B, so it can access the "extends Base<Integer>" portion of the
code to know what T is.  This is the second part of the work.

Anyways, I hope my message isn't too loquatious.  Just trying to see if
anyone has tips before i try to hack at the code alone.  Also entertaining
tips on how to make the implementation clean (e.g. i'm not passing tons of
class hierarchy / context information around).  I'm toying currently with
the idea with adding another layer between FieldMetaData and the type of the
field with something like :

abstract class Type { public Class<?> resolve(Class<?> context); }
class ConcreteType { ... }
class GenericType { ... }

Hopefully the names will explain themselves.  ConcreteType is used for a
non-generic field, and can have a lightweight implementtation , while all
the generics resolution work is done in the GenericType class.  Then the
FieldMetaData will only contain instances of Type, instead of Class<?>.

--Atanamir
-- 
View this message in context: http://openjpa.208410.n2.nabble.com/Generics-Support-tp5049201p5061239.html
Sent from the OpenJPA Developers mailing list archive at Nabble.com.

Mime
View raw message