|
From: Doug C. <de...@fl...> - 2002-02-06 05:06:07
|
Tuesday, February 05, 2002, 10:23:19 PM, Gavin wrote:
> Doug Currie, who was working on the reflective map generator will be
> affected most affected by the new mapping style and by deprecation of
> Persistent. Presumably some user input is no required in order to determine
> what classes are entities, which are components, which are to be
> serialized.
Yes. I currently use Persistent in two ways.
1. When computing the inheritance graph. As classes are added to the
set to be analyzed, I construct this graph (well, actually a set of
trees since Java is single inheritance). The lack of a Peristent
interface tells me when to stop climbing superclass links to insure
that all requisite classes are included.
2. When determining the role of a property which is a reference to an
object. If the object's class implements Persistent, then it's an
association. Otherwise it's something else. Details below.
Workarounds are possible for each of these, but they're not nice.
Currently it is only necessary to provide MappingByReflection the
fringe of the inheritance graph. We could insist that all classes to
be analyzed are provided, but this could lead to errors (missing
superclasses; holes in the graph -> extra tables which are too
sparse).
Currently the following must be true of a class before it is added as
a persistent [super]class:
the class
C1. is not Primitive
C2. is not an Array
C3. is not an Interface
C4. is not nested (an inner class), i.e., c.getDeclaringClass() == null
C5. is not Abstract
C6. has a public default constructor (0 arguments)
C7. implements Persistent
What can we replace #7 with to limit the search? One possibility is
the class must be in the same toplevel package. E.g., system classes
would never be persistent. Opinions? Suggestions?
Determining property roles is much more difficult. Currently I am
using the following heuristic, some of which is based on the logic in
Hibernate.auto...
1. Hibernate.basic(cls) != null => BASIC_KIND
2. cls.isArray() => ARRAY_KIND
3. Type.class.isAssignableFrom(cls) => CUSTOM_KIND;
4. Persistent.class.isAssignableFrom(cls) => ASSOCIATION_KIND
5. PersistentEnum.class.isAssignableFrom(cls) => ENUM_KIND
6. java.util.List.class.isAssignableFrom(cls) => LIST_KIND
7. java.util.Map.class.isAssignableFrom(cls) => MAP_KIND
8. java.util.Set.class.isAssignableFrom(cls) => SET_KIND
9. Serializable.class.isAssignableFrom(cls) => SERIALIZABLE_KIND
10. else if C1..C6 above are true => COMPONENT_KIND
11. else UNKNOWN_KIND (error)
As Gavin points out, without Persistent, it is impossible to
distinguish ASSOCIATION_KIND from COMPONENT_KIND.
But, the above heuristic has other problems. It cannot distinguish
SERIALIZABLE_KIND and COMPONENT_KIND -- the choice is arbitrary if
both modes are possible. It also cannot determine if collections and
arrays should be keyed (top level) or unkeyed.
It is also impossible for MappingByReflection to see inside lists,
maps, and sets. Because they must be declared by their basic
collection interface, the reflection code has no clue what they
contain.
So, my conclusion is that using the Hibernate style of persistence,
reflection will give us only very limited information. Removing
Persistent will hurt, but it is only one of many issues.
I plan to continue working on the MappingByReflection code in the hope
that someone will step forward to implement a GUI front end where some
of this missing information can be interactively supplied.
As a snapshot of its current status, MappingByReflection produces the
XML output below given the args[]...
cirrus.hibernate.test.Qux
cirrus.hibernate.test.Foo
cirrus.hibernate.test.Foo$Struct
cirrus.hibernate.test.Bar
cirrus.hibernate.test.Baz
cirrus.hibernate.test.Qux
Note that I have implemented a heuristic to find the UID property,
another shortcoming of reflection. I think everthing except nested
arrays and top level collections is basically working. I do need to:
check for duplicate table and column names and repair them, and add a
length to String and Binary columns.
e
-=-
<!-- Class cirrus.hibernate.test.Foo$Struct isn't Persistent! -->
<!-- cirrus.hibernate.test.Qux already added -->
<hibernate-mapping>
<!-- cirrus.hibernate.test.Qux root -->
<class name="cirrus.hibernate.test.Qux" table="Qux" select="distinct">
<id name="key" type="long" column="key">
<generator class="hilo.long"/>
</id>
<property name="deleted" column="deleted" type="boolean"/>
<property name="stuff" column="stuff" type="java.lang.String"/>
<property name="created" column="created" type="boolean"/>
<property name="loaded" column="loaded" type="boolean"/>
<property name="stored" column="stored" type="boolean"/>
<!-- association name="foo" type="cirrus.hibernate.test.Foo" -->
<property name="foo" column="foo" type="cirrus.hibernate.test.Foo"/>
<set role="fums" table="fums">
<key column="uid"/>
<element column="elm" type ="java.lang.String"/>
</set>
<list role="moreFums" table="moreFums">
<key column="uid"/>
<index column="i"/>
<element column="elm/>
</list>
</class>
<!-- cirrus.hibernate.test.Foo root -->
<class name="cirrus.hibernate.test.Foo" table="Foo" select="distinct" discriminator="subclass">
<id name="key" type="java.lang.String">
<column name="key" length="16"/>
<generator class="hilo.hex"/>
</id>
<property name="binary" column="binary" type="[B"/>
<property name="string" column="string" type="java.lang.String"/>
<!-- array of basic name="custom" type="java.lang.String" -->
<array role="custom" table="custom">
<key column="uid"/>
<index column="idx"/>
<element column="elm" type ="java.lang.String"/>
</array>
<property name="blob" column="blob" type="java.io.Serializable"/>
<property name="int" column="int" type="int"/>
<property name="timestamp" column="timestamp" type="java.util.Date"/>
<property name="short" column="short" type="java.lang.Short"/>
<property name="yesno" column="yesno" type="boolean"/>
<!-- cirrus.hibernate.test.FooComponent -->
<component name="component" class="cirrus.hibernate.test.FooComponent">
<!-- cirrus.hibernate.test.FooComponent -->
<component name="subcomponent" class="cirrus.hibernate.test.FooComponent">
<!-- cirrus.hibernate.test.FooComponent -->
<component name="subcomponent" class="cirrus.hibernate.test.FooComponent">
<!-- component too deeply nested name="subcomponent" type="cirrus.hibernate.test.FooComponent" -->
<property name="name" column="name" type="java.lang.String"/>
<property name="count" column="count" type="int"/>
<!-- array of basic name="importantDates" type="java.util.Date" -->
<array role="importantDates" table="importantDates">
<key column="uid"/>
<index column="idx"/>
<element column="elm" type ="java.util.Date"/>
</array>
</component>
<property name="name" column="name" type="java.lang.String"/>
<property name="count" column="count" type="int"/>
<!-- array of basic name="importantDates" type="java.util.Date" -->
<array role="importantDates" table="importantDates">
<key column="uid"/>
<index column="idx"/>
<element column="elm" type ="java.util.Date"/>
</array>
</component>
<property name="name" column="name" type="java.lang.String"/>
<property name="count" column="count" type="int"/>
<!-- array of basic name="importantDates" type="java.util.Date" -->
<array role="importantDates" table="importantDates">
<key column="uid"/>
<index column="idx"/>
<element column="elm" type ="java.util.Date"/>
</array>
</component>
<property name="zero" column="zero" type="float"/>
<property name="bool" column="bool" type="boolean"/>
<property name="nullBlob" column="nullBlob" type="java.io.Serializable"/>
<property name="null" column="null" type="java.lang.Integer"/>
<property name="bytes" column="bytes" type="[B"/>
<!-- enum name="status" type="cirrus.hibernate.test.FooStatus" -->
<property name="status" column="status" type="cirrus.hibernate.test.FooStatus"/>
<property name="long" column="long" type="java.lang.Long"/>
<property name="integer" column="integer" type="java.lang.Integer"/>
<!-- association name="foo" type="cirrus.hibernate.test.Foo" -->
<property name="foo" column="foo" type="cirrus.hibernate.test.Foo"/>
<property name="byte" column="byte" type="java.lang.Byte"/>
<property name="boolean" column="boolean" type="java.lang.Boolean"/>
<property name="date" column="date" type="java.util.Date"/>
<property name="double" column="double" type="java.lang.Double"/>
<property name="float" column="float" type="java.lang.Float"/>
<!-- cirrus.hibernate.test.Bar -->
<subclass name="cirrus.hibernate.test.Bar">
<property name="barString" column="barString" type="java.lang.String"/>
<!-- cirrus.hibernate.test.FooComponent -->
<component name="barComponent" class="cirrus.hibernate.test.FooComponent">
<!-- cirrus.hibernate.test.FooComponent -->
<component name="subcomponent" class="cirrus.hibernate.test.FooComponent">
<!-- cirrus.hibernate.test.FooComponent -->
<component name="subcomponent" class="cirrus.hibernate.test.FooComponent">
<!-- component too deeply nested name="subcomponent" type="cirrus.hibernate.test.FooComponent" -->
<property name="name" column="name" type="java.lang.String"/>
<property name="count" column="count" type="int"/>
<!-- array of basic name="importantDates" type="java.util.Date" -->
<array role="importantDates" table="importantDates">
<key column="uid"/>
<index column="idx"/>
<element column="elm" type ="java.util.Date"/>
</array>
</component>
<property name="name" column="name" type="java.lang.String"/>
<property name="count" column="count" type="int"/>
<!-- array of basic name="importantDates" type="java.util.Date" -->
<array role="importantDates" table="importantDates">
<key column="uid"/>
<index column="idx"/>
<element column="elm" type ="java.util.Date"/>
</array>
</component>
<property name="name" column="name" type="java.lang.String"/>
<property name="count" column="count" type="int"/>
<!-- array of basic name="importantDates" type="java.util.Date" -->
<array role="importantDates" table="importantDates">
<key column="uid"/>
<index column="idx"/>
<element column="elm" type ="java.util.Date"/>
</array>
</component>
</subclass>
</class>
</hibernate-mapping>
|