Hi Blaise, All,
I
think for most of the companies in the TC, integration with JAXB is an
absolutely critical usecase. And since it's so important, everyone either
already has or is going to implement something to support this use case.
The motivation for standardizing JAXBHelperContext in 3.0 is that
1) It makes SDO stronger, since there is a standard way
to handle a critical use case.
2) It will only get harder to standardize it in the
future, since everyone with an existing solution and we will have a hard time
finding a solution that will be "backwards compatible" for
everyone.
That said, maybe it is a good idea to defer this
proposal at least until we have some framework proposal for creating
HelperContexts.
What this means as far
as the vF2F agenda is that the discussion of "integration with standard
representations" will be limited to low level XMLHelper methods, such as
creating and processing XMLStreamReaders and
ContentHandlers.
Does everyone agree with
this approach?
Ron
Hi Ron,
For our implementation wrap is based on object
identity not equals()/hashCode(). Below is some JUnit code adapted from
one of our test cases to demonstrate.
assertEquals(p1,
p2); assertNotSame(p1, p2);
DataObject p1DO = jaxbHelperContext.wrap(p1); DataObject
p2DO = jaxbHelperContext.wrap(p2); assertNotSame(p1DO,
p2DO);
@XmlID (from JAXB) does not factor into identity past the
scope of a load/save operation. It is unlike @Id (from JPA) where POJOs
with the same ID value are strongly related in that they correspond to the same
row in some table.
Managing the scope of JAXBHelperContext is
important. For our implementation weak references are used where
possible. We also see the need for additional APIs to allow POJOs to be
dereferenced under the user control.
Some of the changes being proposed
by Frank appear to be making it easier for users to control
HelperContexts. This work might alleviate some of your concerns in that
area.
I'm not sure I see the value in making JAXBHelperContext part of
the SDO specification. Again with potential changes to HelperContext
creation, it could become possible for implementors to offer special purpose
HelperContexts like this for handling of things like JAXB objects, XML,
EMF, etc.
-Blaise
Barack, Ron wrote:
7C3EF93EEBC6EB4A8B4470853DE865665EEDD6@dewdfe18.wdf.sap.corp
type="cite">
Hi Blaise,
Some more questions on your implementation of
JaxbHelperContext
hc.wrap(Object) always returns the same DataObject
for the same pojo. Does this rely on the equals() and hash() methods as
implemented in the class? Imagine 2 pojos, where p1!=p2 but
p1.equals(p2). Would hc.wrap(p1)==hc.wrap(p2)? What about if
p1.class has some @XmlID field?
Looking at your sample, it's a little hard to discern
the lifecycle of the JaxbHelperContext. Because constructing the types
is expensive (involving parsing XSDs, etc), I normally think of HelperContexts
as having to be thread-safe and shared, like a JAXBContext, or like a
classloader. For instance, when a session bean uses SDO, there
would be one HelperContext that are shared by all instances of the bean.
I believe this to be the common
understanding. The sample code is of course a simple
client; it's impossible to tell if the JaxbHelperContext is meant to
shared.
I think there is reason to have maybe
JaxbHelperContext be a sort of lightweight context, that is meant to be owned
by a single client. We could have a heavyweight context, with types
defined by the XSD. The heavyweight context could have a
method, something like
HelperContext.getJaxbHelperContext(JAXBContext). The JaxbHelperContext
would basically delegate to the heavyweight context, except when doing things
like constructing instances, or implementing wrap() or
unwrap().
This gives me something like a binder, a client
object that I can use to control the scope and lifetime of the POJO ->
DataObject map. But without defining a new "Binder"
interface.
Any comments?
Ron
Hi
Ron,
From our perspective JAXBHelper context is the POJO Helper
Context.
Assuming the POJOs are also JPA entities, then wrapping (as
opposed to copying via an XML step) need not trigger all the lazy
relationships (of course this could be implementation dependent). With
regards to wrapping and the performance of getters/setters, there are some
ways to do this with reasonable performance.
The POJO as a DataObject,
this is an interesting concept. One problem I see with this is that
DataObjects do a lot of relationship management that most POJOs don't do (i.e.
adding a DataObject to a new container automatically removes it from the old
container). Here the weaving is not invisible to the user and may not
match the users expecations.
The XSDHelper.define() call is necessary,
because as you have previously mentioned XML schemas generated from POJOs do
not contain all the information required by SDO. One example is
specifying datatype=false/containment=false properties, that require SDO
annotations on the XML schema.
Does DataObject
customerDO = hc.wrap(customer); always return the same DataObject? In our implementation wrap always returns the same
DataObject. This does require some management, but with proper attention
to object identity, and avoiding hard references it is doable. Not sure
how a "binder" solution avoids this as something JAXB like would require a
one-to-one correspondence between a POJO and a DataObject.
What happens if a wrapped POJO is modified?
Our
customer base is not interacting with both the POJO and the DataObject at the
same time. If they were you are correct that weaving could be used to
apply the changes made to the POJO back to the DataObject.
Is there
any way to start with a DataObject, and generate a JAXB from it? Yes,
this was the main reason for making the entry point its own
HelperContext. DataFactory.create() creates DataObjects that wrap POJOs,
and XMLHelper loads DataObjects that wrap POJOs.
Usage of
StAX The usage of StAX does not automatically create a Java SE 6
dependency. JAXB 2.0 based on Java SE 5 makes use of these APIs, it just
requires implementors to ship the StAX (JSR 173) API jar. I think SDO
should offer the same marshal/unmarshal options as JAXB. But the
decision to change the base Java SE version is independent from our inclusion
of StAX.
User Expectations of the XML representation of
POJOs You are correct in your model that the user must specify JAXB
information to get the desired XML representation. This is exactly the
role of JAXB in the larger world of Java EE. Today users are retrieving
data from relational databases as POJOs using JPA, and exposing this data
through services as XML using JAXB.
SDO competing with
JAXB If SDO takes a POJO graph and has its own XML representation then
yes it is competing with JAXB. Regardless of the algorithm it is
impossible to guess the XML schema representation of a set of POJOs, as such
annotations are required fix it. With your proposal SDO annotations
would be required to adjust the XML Schema representation of a set of POJOs,
again this competes with JAXB.
Advantages of our
Approach
- A single integration point between SDO and Java EE (JAXB annotated
POJOs), as opposed to point integrations for JAXB/JPA/POJO/etc.
- No SDO POJO annotations required. Instead the integration point
between JAXB/Java EE and SDO is the XML schema.
- SDO becomes a value add to JAXB/Java EE introducing enriched metadata,
relationship management, dynamic APIs, change summary, etc.
- No changes are required to existing Java EE applications (that already
expose data as XML) to make them compatible with SDO. This is what our
customers want, a mechanism to make their existing Java EE applications
compatible with SDO enabled middle-ware
plumbing.
-Blaise
Barack, Ron wrote:
Hi Blaise,
Over the year, I've personally become less convinced of
the wrapping approach, as opposed to providing some kind of optimized data
transfer. What do you see as the advantage of wrapping over some kind of
convert operation? Instead of wrapping the POJOs, I could mashal them
in JAXB, and load them using XMLHelper. Does wrapping give me
something here I could not get through such a mechanism (modulus
performance)? And of course because of the second point below,
the getters and setters could become significantly more expensive,
offsetting the gains made in avoiding a conversion step.
There is a third approach, and that is for the
framework to weave the POJO classes, so that "new Customer()", or at least
ObjectFactory.createCustomer() returns an object that already implements
DataObject. It seems to me this is a straightforward extension of JPAs
approach. In our JPA integration, you turn on this bytecode
enhancement with a flag in persistence.xml. Do you think it would be
possible to get to this level of integration with JAXB?
Either way, I have some questions to the
details:
Why is the call to XSDHelper.define() necessary?
Couldn't the metadata be introspected from the POJOs (ala
generateSchema())? Isn't there a danger of the XSD being out of sync
with the classes (similar to your comment regarding the @schemaLoc
annotation?
Does DataObject customerDO = hc.wrap(customer);
always return the same DataObject? It's maybe a implementation
detail, but does wrap create the DataObjects lazilly or all at
once? If you do it lazilly, you
need to
maintain a map from the POJO object to the DataObject wrapper, right?
Otherwise as we navigate around, we could wind up with the same POJO having
2 DataObject wrappers. And such a map raises a bunch of ugly lifecycle
issues. This is where I thought something like a binder could come
come in handy, as a way of putting the lifecycle in the hands of the
client.
What happens if a wrapped POJO is modified?
Obviously, calls to DataObject.get() would see the changes, but what about
things like change tracking, containers, and bi-directional properties,
that, in SDO happen implicitly when a setter is called? Are you
"weaving" the byte code of the JAXB POJO?
Is there any way to start with a DataObject, and
generate a JAXB from it? Ie, can I unwrap something that hasn't been
wrapped? When I create a DataObject using DataFactory.create(), does
it automatically create an underlying POJO?
Regarding the StAX and JAXB dependencies.
I guess it will be 2010 before any SDO 3 implementations are released
as products... I imagine by that time pretty much everyone will be on
JSE 6. Maybe we should consider raising the minimum compatible JSE to
JSE 6. What do you think?
You mention that
customers have expections about the XML representation of POJOs. What
about POJOs that are not organized into a containment structure? Eg,
my example:
class
School {
List<Student> getStudents() {...}
List<Course> getCourse() {...}
}
class Course {
School getSchool() {...}
List<Student>
getStudents() {...}
}
class Student
{
School getSchool() {...}
List<Course> getCourses() {..}
}
what do your customers
expect from the XML representation of School? AFAIK, the programmer
has to specify the XML containment structure as part of the model, He must
annotate give the object ID properties, and he must use @XmlID to indicate
non-containment. I don't think SDO is competing with JAXB if it
specifies a mechanism through which such graphs can be marshalled to
XML. SDO 3 offers 2 such mechanisms: the graph could be placed
inside an container with orphan properties, and the containment structure
(or alternate structures) can be imposed on the model through the project
method. Offering this kind of fuctionality is one reason to include an
SDO-POJO binding in SDO 3.
Best
Regards,
Ron
Hi
Ron,
I'm glad you raised this email thread. Integration with
JAXB (POJOs) is also an important use case to Oracle and in particular the
EclipseLink SDO implementation.
Both SDO and JAXB have an XML schema
representation of their metadata. For us this is the join point
between these two technologies. EclipseLink DataObjects are capable of
wrapping POJOs, actions applied to the DataObjects (set/unset/detach/etc.)
are automatically applied to the underlying POJO. I have included some
code below to demonstrate: // JAXB - Create
the JAXB Context JAXBContext jaxbContext =
JAXBContext.newInstance("com.example.customer");
// SDO - Create the JAXB aware HelperContext
HelperContext hc = new JAXBHelperConext(jaxbContext);
hc.getXSDHelper().define(customerXSD); //
SDO - Wrap the POJO in a DataObject Customer customer
= new Customer();
customer.setLastName("Doe"); DataObject customerDO =
hc.wrap(customer);
// SDO - Create and modify
DataObjects
customerDO.getString("last-name"); // returns
"Doe" customerDO.setString("first-name",
"Jane"); DataObject addressDO
customerDO.create("address");
addressDO.setString("street", "123 Any
Street"); // SDO - Unwrap the
POJOs // Note: customer ==
hc.unwrap(customerDO) Customer customer2 = (Customer)
hc.unwrap(customerDO); I would prefer to not
invent a POJO to SDO binding. Our customers have expectations about
the XML representation of POJOs. As JAXB is included in Java SE 6, I
imagine many people share these expectations. If Java objects save to
XML one way, the act of wrapping them in (or converting them to) DataObjects
should not change the XML representation. Of course if users choose to
make use of concepts such as ChangeSummary then the XML representation
begins to diverge but in predictable and explainable ways. For us it
is imperative that SDO provides a compatible value add to Java EE, and not
become a competitor to any of its technologies.
Other Points:
- I agree JAXB annotations do not contain enough metadata to reproduce
all SDO metadata. For example JAXB cannot represent the property
index of attribute properties.
- JAXB classes generated from XML schema can contain properties that are
different from SDO class generation. Especially wrt choices and
substitution groups.
- JAXB is primarily concerned with Java classes, while SDO is concerned
with Java interfaces.
- More load/save targets (such as StAX) would be great. Of course
StAX is not included with Java SE 5, and would introduce a new dependency
jar. JAXB has this same requirement and goes away with Java SE 6, so
this may not be a big concern.
- The JAXB Binder maintains a link between POJOs and DOM nodes.
Once linked you can make changes on one side and then make an explicit
call (it doesn't happen automatically) to apply the changes to the other
side. While useful the default JAXB algorithm isn't always what
users expect. Our implementation provides the user with the choice
of 3 different "binding" algorithms.
-Blaise
Barack, Ron
wrote:
Hi Everyone,
The idea of using JAXB annotations as a
solution to ISSUE 22, even of consolidating static SDO and JAXB, has come
up repeatedly in the calls. I think we may be able to make better
progress in this regard by discussing the ideas per email, so that there
is a permament record of the arguments. Having this discussion now
will hopefully make the discussion during the F2F more
productive.
First I want to say that integration with JAXB
is a high priority issue for us, but this integration may take several
forms:
1. Transfering data between the
representations 2. JAXB
annotations as a source of SDO metadata 3. JAXB classes as static SDOs
Of course, it is desireable to have as deep and
integration as possible. When I first started thinking about the
problem, I set out to achieve all three types of integration. After
long consideration, I arrived at the conclusion that only the first is
really possible.
About the first point I hope there is general
agreement: Applications that use SDO as a data representation must be able
to transfer data with applications that use JAXB. In some ways, this is
already possible in 2.1: all you need to do is mashall to XML. This
approach introduces some performance costs, and I think we should address
steamlining the process in SDO 3. One approach that we've found to
be very helpful is for SDO to be able to produce an XMLStreamReader which
in turn can be fed into a JAXB marshaller. For maintaining an active
map between the representations, I believe a DOMBinder is a very promising
approach, and possibly we could go a step further and have a JAXB
binder. (Unfortunately, I believe the JSE implementation of JAXB
still has an incomplete version of the DOMBinder
functionality).
Similarly, clients can already use JAXB
annotations as a source of SDO metadata under SDO 2.1, at least whereever
JAXBContext.generateSchema works it is possible to use XSD as an
intermediate metadata format. However, it is important to realize that
JAXB does not provide the level of details we expect to see in a
resolution to ISSUE 22. JAXB annotations capture exactly the
information necessary to correctly marshal and unmarshal to XML.
Restrictions (facets), and all reference to the original simple type is
lost. JAXB creates String properties for xs:NCName, xs:AnyURI, etc.,
and there is no way to get back to the original type through reflection on
the JAXB object.
JAXB objects reflect the purpose of JAXB, which
is to create an XML binding for Java. XML models, and therefore
JAXB, do not contain (as a rule) bi-directional or non-containment
references. It's true that XML and JAX can represent non-containment
relationships using @XmlID, but in SDO non-containment relationships are
not limited to objects that have ID properties (or even keys).
If we were to use JAXB annotations as the
standard way to represent SDO metadata in Java, then we are also accepting
the default behaviour associated with the *absence* of these
annotations. In JAXB, an unannotated POJO class that references a
second POJO class is intepreted as there being a containment relationship
between the associated types. I would argue that this should not be
the default behaviour for SDO. If it were, then we loose the ability
to to take an arbitrary model based on unannotated classes, pack them in a
DataGraph (or anything else that has an orphan property) and being able to
generate XML for the model. The assumption of containment
relationships means that we will get cycles and other problems, making the
whole approach unworkable.
A further problem is that I think we would
probably be misusing the JAXB annotations. Static SDOs may be
interfaces or generated classes. JAXBs are annotated POJOs
(JavaBeans).
Finally, very pragmatically, the JAXB spec is
large and complex. Expecting implementations to make sense of the
annotations and their many combinations is a very high bar indeed, even
more so when we expect to enrich the annotation set with some of our own
annotations.
Having rejected the second point, perhaps the
discussion of the third point is moot, but I want to discuss it because
the appeal of the approach is so strong. The appeal can be
summarized as follows: "The JSE already defines a standard XML to
Java binding. By defining static SDOs, we are defining a competive
functionality that is therefore doomed to be rejected by the java
community. The problem with this argument is that static SDOs do not
represent an XSD, they represent SDO metadata. Although a large part
of the SDO spec contains the mapping between the metamodels, the models
are not the same, not is the SDO metamodel a subset of the XSD metamodel
(multiple inheritence, bi-directional relationships being two examples of
constructs that do not exist in XSD).
On a more practical level, although for very
simple XSDs the classes generated by JAXB and the static SDOs defined in
SDO 2.1 are compatible, we very quickly come to places where the models
diverge. SDO represents choices as several parallel properties, and
we expect the user to fill one or the other. JAXB generates a sort
of combined property (using the pattern "getAorB"), and the user must
create an JAXBElement and use this value to set the property. It
would be very odd to have this structure reflected in the static SDO when
it is missing from the SDO metamodel. In cases such as those where
we create a sequenced DataObject, JAXB creates an class with a single
getContent() method. Static SDOs, like SDO itself, maintains in such
cases a property oriented view of the data in addition to the sequenced
view.
I hope this gets the discussion going so that
we can decide what sort of integration with JAXB we are aiming for,
whether or not we we need to define our own annotations, etc.
Blaise, as a member of the JAXB EG, I'm particularly interested in your
comments.
Best Regards, Ron
|