JAXB with inheritance but without using child element names - java

I am working with XML from a vendor system that I cannot change and I am trying to use JAXB with it. The XML is used in a REST like API. See below for a couple message examples. Each request/message has the same root element name that is called MsgRequest and it contains a couple common elements that are in every request but it also contains elements that are dependent on the message type.
<!-- request 1 -->
<MsgRequest>
<SubType>GetUser</SubType>
<RequestID>1</RequestID>
<UserName>joe</UserName>
</MsgRequest>
<!-- request 2 -->
<MsgRequest>
<SubType>GetCompany</SubType>
<RequestID>2</RequestID>
<CompanyName>joe</CompanyName>
</MsgRequest>
From Java perspective I could model it like this using inheritance.
class BaseMessage {
String subType;
Integer requestID;
};
class GetUserMessage {
String userName;
};
class GetCompanyMessage {
String companyName;
};
I don't understand how I would use JAXB to represent this XML. I have done some research and found XMLElementRef but that will marshal the name of the referenced element which is not what I want.
Hopefully I am missing something obvious. Any suggestions appreciated.

XML wasn't designed to fit any particular language or even paradigm. This means thatbut you can design an XML that can be represented by a Java class hierarchy but there's no guarantee that some XML structure that comes your way can be mapped to a class hierarchy. Consider that an XML parser must be able to determine the (complex) type of an XML element from the element's tag name. So, if you have two elements tagged <MsgRequest>, they'll have to be mapped to a single Java type.
You can write an XML Schema for a single complex type with required fields subType and requestID, and optional (minOccurs=0) fields userName and companyName. It won't be good OO style, but it'll generate your XML.

Related

How to use special characters in XML tag like <abc-name> using JAXB?

I have one requirement where I need to generate XML from JAXB.
I have used basic object where we have only key value pair with parent child relationship but never encountered situation like below.
Expected XML
<swExtended>
<swx-mandatory>FALSE</swx-mandatory>
<swx-period/>
</swExtended>
In Java Object, I dont know how to name tag with special character <swx-mandatory> while defining java variable.
As BretC mention, Answer was very simple
#XmlElement(name = "dave-123")

Serializing java objects with respect to xml schema loaded at runtime

I call an XML document three-layered if its structure is laid out as following: the root element contains some container elements (I'll call them entities), each of them has some simpleType elements inside (I'll call them properties).
Something like that:
<data>
<spaceship>
<number>1024</number>
<name>KTHX</name>
</spaceship>
<spaceship>
<number>1624</number>
<name>LEXX</name>
</spaceship>
<knife>
<length>10</length>
</knife>
</data>
where spaceship is an entity, and number is a property.
My problem is stated below:
Given
schema: an arbitrary xsd file describing a three-layered document, loaded at runtime.
xmlDocument: an xml document conforming to the schema.
Create
A Map<String, Map <String, Object>> containing data from the xmlDocument, where first key corresponds to entity, second key correponds to this entity's property, and the value corresponds to this property's value, after casting it to a proper java type (for example, if the schema sets the property value to be xs:int, then it should be cast to Integer).
What is the easiest way to achieve this result with existing libraries?
P. S.
JAXB is not really an option here. The schema might be arbitrary and unknown at compile-time. Also I wish to avoid an excessive use of reflection (associated with converting the beans to maps). I'm looking for something that would allow me to make the typecasts while xml is being parsed.
I think XMLBeans is worth a shot; saved the day more than once...
Basically you run an ant script to generate the beans handling the schema, then you iterate over the nodes to build your map.
I think JAXB (tutorial here) is the easiest way to do this.
Create your XML structure like:
#XmlRootElement
class data {
public List<SpaceShipType> spaceship;
public KnifeType knife;
}
class SpaceShipType {
public int number;
public String name;
}
class KnifeType {
public int length;
}
Then create the object tree, and use JAXB.marshall() to write the XML.
If you have an existing XSD, use the xjc tool to create the classes for you.
You will need reflections if the schema is unknown at compile time.
I suggest to take a look at some other tools like xstream.
I could recommend the simple framework or you could do parsing/wrinting xml with pure dom4j as I did in the timefinder project. I used the 'pure' approach because I had cycles in my object graph, but I wanted that the xml could be validated with an xml schema (and I did not want to use JAXB)
I have finally went with using Castor library for parsing the schema and assigning data types manually.

JAXB - Add a node to the XML as html link

I have a basic JavaBean in my service layer and originally it was not designed for marshalling. This object is used by both JAX-WS, JAX-RS, and Servlets in other layers of my application. I want to take advantage of a drill down type effect in my REST services so my question is: How do I make one of the fields/properties of the javabean appear in the xml as an HTML Link? Obviously I need to use CData. I cannot modify the original javabean by adding fields, etc. Is there an annotation I can use?
If I have in my class:
...
String data;
...
how do I make that(in xml):
<data><![CDATA[ValueOfData]]></data>
is this possible with JAXB and Annotations? Maybe xlink?
I suggest using a type adapter. These are normally used to adapt XML string values into more strongly-typed values like timestamps, but you can also use them to adapt strings to strings.
First, create a subclass of javax.xml.bind.annotation.adapters.XmlAdapter. This class will have to implement marshal and unmarshal, converting to and from the value of your field, and the HTML fragment in the XML.
Once you have that, you can annotate your field with
#XmlJavaTypeAdapter(MyAdapter.class)
And that should be it.

Duplicate namespace declarations in JAXB generated XML

I am using JAXB to generate XML from Java objects, it's a realtime, quite high message rate application and works fine most of the time. However occassionally and without any obvious clues as to why, I am getting duplicate namespace declarations in the generated XML. eg:
<UpdateRequest xmlns="http://xml.mycomp.com/ns/myservice"
xmlns="http://xml.mycomp.com/ns/myservice">
<field1>value</field1>
...
</UpdateRequest>
Has anyone seen this behaviour before?
Check if the xsd code of this class allow the creation of more than 1 instance of the repeated attribute. if so, you can avoid this repetitions setting the number of instances of the xmlns attribute for each UpdateRequest object.
If the problem is your code (maybe there is being created this attribute twice) and you have limited the number of instances of the attribute (as i said above), the program will show an error at runtime complaining that you are trying to insert an attribute already defined.
A solution might be available at this link.
here's the relevant section quoted verbatim from the above link that may be relevant for you:
Similar explicit inclusion of a schema
type in an instance document's element
occurs if you instantiate a JAXB
element using an object of some
(abstract) XML schema base type so
that the element would have the
element tag of the base type.
Second, avoid xs:anySimpleType since
this will also create multiple
references to the namespaces bound to
xsi and xs, and type attributes
containing the actual type. And you
lose JAXB's advantage of having typed
fields in your Java classes so that
you lose all the checks the Java
compiler might do, and for
unmarshalling you'll have to handle
all the conversions yourself.

How can I get the xml Node type based on schema definition in Java?

Let's say I have a doc.xml and corresponding doc.xsd. I use xpath to retrieve some nodes, so I get a list of org.w3c.dom.Node. How can I get type of each node from schema, eg. xs:integer, xs:string etc ?
Some solution would be to parse schema with xpath query "//NodeName[#type]" using node.getNodeName() as NodeName, but that's not perfect. I can't be sure that schema is elegant - what if NodeName exists in many places in schema and has not been extracted as a separate type?
So generally I am looking for a reliable solution to get the node type for ANY valid xml & xsd.
You should consider using JAXB. It will create Java classes for you based on the schema type. Then your XML docs are read into those classes, which are typed according to how you defined your XSD. Therefore xsd:int maps to java int(or Integer wrapper class, I can't recall), etc.
Cast your DOM Elements to TypeInfo: from there, you can access the type information you're looking for.
Unfortunately types as defined in an XML Schema (XSD) or Document Type Definition (DTD) are not directly tied to XML document they validate. The elements and attributes in an XML document do not inherently have a type they are just text. Think of an XSD as a script that validates an XML document rather than a set of type annotations for elements and attributes.
The XML specification does not define types as you are thinking of them here. Even Document Type Definitions (DTD) which can be embedded inside XML documents more about the structure of the document not the type of the data contained in elements and attributes.
The type system described in XML Schema is an optional layer of validation that can be applied to XML documents. Since this validation optional the standard XML APIs do not provide a way to bind the validation rules in an XSD to the actual attributes and elements.
I think it would be possible for an XML API to provide a mechanism to bind an XSD to a specific XML document, but I am not aware of an XML parser that does this. One reason why this is not so easy is that the type system that is defined in XML Schema is much richer than is supported in most mainstream programming languages. In your example you may only be interested in xs:integer, xs:string and the like but in XML Schema you can create types that specify ranges, patterns and other things that are just not possible with data types in most programming languages. To represent this complex type system in Java or any programming language would have to be done through a fairly complex API. The the question becomes it is really worth it? I would say probably not.
As per David Ds answer, slightly cleaner, call getSchemaTypeInfo() on an element or attribute

Categories