Wolfgang,
hopefully I expect least people to use <e> as a document root, so if that
case will happen, it seems the caller has no chance at all to fix it. Sad,
but true. Would be great if the JAXB specification one day would allow to
use an adapter with a document root. Personally, I think the possibility to
completely split between ValueType and BoundType is a great and useful
paradigma of JAXB and it should be useful everywhere.
About writing JAXB by hand: I started with a XJC-centric approach, but the
created code was more or less a mess. For example, the schema (DTD) said
that <x> can include <y> exclusive-or <z>, but what XJC created was Java
classes that allowed to set both at the same time (not mutually exclusive as
wanted by the DTD) and even worse, it abstained from creating some classes
but just used untyped Object references, so people could not typesavely use
the result or could try to build object trees containing invalid Java
Objects. Also, the readability of the created code was a mess. As I wrote
before, what I want to provide is a fool-proof API (including brilliant
JavaDocs pointing to the original documentation, prevent leaving out
mandatory parameters, prevent "empty" objects where the spec wants them to
be non-null in any case, etc.), while the result was just, well, a mess.
Possibly an JAXB expert would be able to tune the binding in such a way that
the result would come near to what I wrote by hand. But I doubt that it
would be as perfect and readable and rich of JavaDocs as the manual code
is), and I doubt that the XJC customization would be less work. As the DTD
will never change (it did not change for a decade) I also do not see much
sense in an automatic process, since it would be run just once. As the API
has to be stable between releases, so each failure must be worked around
instead of solved, I doubt that the XJC approach would be able to do that
(how to tell XJC that there was a typo in the customization, and you want to
preserve the faulty API but internally re-write it as a workaround to the
resulting problem?).
About the enum tags: As I said, it is a third party schema. The authors
(professors and industry leads) decided to not use <e>v1</e> but
<e><v1/></e>. I don't know why they did it, and I don't actually make up a
mind about it, because neither can I influence it, not can they change it
(as the schema must be stable once it was released). So I have to live with
it, independent of whether it is "strange" or not. Maybe it is just
impossible to express enum values in a DTD, I don't know.
About equal checks: Your view is too value centric. Start seeing it from the
Java programmer's view. An enum is what he expects. An enum guarantees that
it's values can be safely compared using ==. He does not deal with XML, DOM,
Elements or Nodes. He deals with enum values. Nobody would ever expect that
an enum value cannot be compared using ==. I do not see that the Java
programmer has to learn to use equals instead since it is semantically not
what he wants to do. He wants to ask: Is the enum value I received that
particual enum value that I need? He does not want to ask: Did I receive an
XML element containing another particular XML element? That is something
completely different. It is absolutely correct that he does not want to use
equals() but insists on using ==. That has nothing to do with attitudes or
views, but solely with semantic expression. Why do you think that E will not
become a proper Enum? I just turned it into one: Ontop of my proposed
solution, I replaced the singletons by real enum values, making an enum out
of the former class. So technically *it is* a real enum. Nobody ever said
that any XML will be compared using ==. It is just this sole enum we are
talking about. The solution is technically and semantically correct and
there is no need to abstain from using ==.
About Unmarshaller.Listener: That will be a much more complex solution, as
the Unmarshaller.Listener cannot replace *the current* object (as my
solution does) but can just *configure* the current object or it's parent.
So you would nee to provide a lot of code since you have to configure each
reference to <e>, while my solution just is a rather safe "one code line for
all references" solution. :-)
Regards
Markus
From: Wolfgang Laun [mailto:wolfgang.laun_at_gmail.com]
Sent: Samstag, 19. Dezember 2009 16:31
To: users_at_jaxb.dev.java.net
Subject: Re: FW: How to map Java enum to XML element (not #PCDATA) body?
Hi Markus,
On Sat, Dec 19, 2009 at 3:51 PM, Markus Karg <markus.karg_at_gmx.net> wrote:
Wolfgang,
thank you for the link. You are right, @XmlRootElement does not allow
@XmlJavaTypeAdapter according to the specification. In fact, I wonder why,
since it works pretty well.
My experiments have always shown that the adapter is not called if the
annotated element is indeed used as the document root element.
About being a root: Due to the schema, <e> *can* be a root, but typically it
is not (it's one of these flexible "do what you want with this tag" schemas
that I dislike so much). You wrote it is confusing that it is annotated
@XmlRootElement. In fact, I wonder why. Maybe I have misunderstood the idea
of this annotation, but I always thought that it marks an element that
potentially *could* be a root. Is that wrong? Do I have to remove it unless
it *must* be a root?
Well, if the schema says it can be, then you'll have to follow suit. (But
note my above remark.)
And what do you mean with "strange" combination? I have a schema describing
the format of a XML file that another software is providing. I am writing a
software that must read / write that file format. So what is so strange
about the fact that I may not change the schema? Or what is strange about
the fact that I want to compare an enum quite as usual using "if (x ==
e.V_1)" instead of writing "if (x.equals(e.V_1))"?
Not being able to change a schema isn't the point. - Given a schema, the
usual procedure is to use xjc to compile it into Java code, and that's it.
So, somewhat unusual is your choice of hand-coding the equivalent Java
classes.
The really strange thing is that the schema appears to map an enumeration to
a choice of elements, using the tag names (v1,...) to represent the
enumeration values. The usual technique is to use a xs:string with a set of
xs:enumeration facets, which xjc would indeed compile into a Java enum
class.
Java programmers (have to) learn that object equality cannot be tested using
==, and presumably they'll have to use equals() for all other XML elements
of that schema. In spite of all your efforts to cover the schema author's
(IMHO: ill-advised) design decision, E is not going to become a proper Java
Enum<?> subclass.
For the Unmarshaller.Listener: As I explained several times, the code is
called by third parties, so I cannot enforce what you wrote. If one of them
forgets to register the Unmarshaller.Listener, then my hotline will be
called. This is costs that I want to prevent if any possible. Hence, a
selfcontained solution is needed.
I merely mentioned it "for the record". (I do understand that you just
provide an API - although this might include wrappers for marshalling and
unmarshalling.)
Cheers
Wolfgang
Regards
Markus