In orderService, we see both
Order.java and OrderRepresentation.java: what’s the difference?
·
Order.java
is the POJO for use inside the application, not to generate XML that goes out.
·
OrderRepresentation
is the POJO that drives the external representation in XML. It has the JAXB
annotations.
OrderRepresentation.java in
orderService: every child element is
annotated, and XMLRootElement is there for JAXB to use this class for
deserialization of an <order> with the right namespace. Also,
item and location are marked as “required = true”, in an attempt to specify
proper behavior, but JAXB without validation pays no attention to this
requirement, or the order of the child elements. It would be enforced if we turned on
validation.
=======================================================================================================
package com.restbucks.ordering.representations;
…
@XmlRootElement(name = "order",
namespace = Representation.RESTBUCKS_NAMESPACE)
// Make sure the schema type is
in the same namespace, to allow a simple schema
@XmlType(name = "orderRepresentation", namespace =
Representation.RESTBUCKS_NAMESPACE)
// FIELD access is better in
general for us, so override default PUBLIC_MEMBER
// (but when we put @XmlElement
on each field, it doesn’t actually matter)
@XmlAccessorType(XmlAccessType.FIELD)
public class
OrderRepresentation {
@XmlElement(name = "id", namespace = Representation.RESTBUCKS_NAMESPACE)
private String id;
@XmlElement(name = "item", required = true, namespace = Representation.RESTBUCKS_NAMESPACE)
private List<Item> items;
@XmlElement(name = "location", required = true, namespace =
Representation.RESTBUCKS_NAMESPACE)
private Location location;
@XmlElement(name = "cost", namespace = Representation.RESTBUCKS_NAMESPACE)
private BigDecimal cost;
@XmlElement(name = "status", namespace = Representation.RESTBUCKS_NAMESPACE)
private OrderStatus status;
/**
* For JAXB :-(
*/
OrderRepresentation() {}
...
But the above approach is not the only way to make all these elements
show up in the XML, in this namespace.
In packages domain and representation we have a file package-info.java
to contain package annotations to set defaults for the whole package. Note that
OrderRepresentation is not depending on its package-info.java in its own
package. In that case we need to specify the namespace over and over for
OrderRepresentation, as you see above. We could simplify these annotation by
depending on package-info.java. Clearly the package defaults are the easy way
to go, especially when you’re using namespaces.
File: package-info.java in
package com.restbucks.ordering.domain
=======================================================================================================
@javax.xml.bind.annotation.XmlSchema(namespace
= "http://schemas.restbucks.com",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package
com.restbucks.ordering.domain;
=======================================================================================================
The package annotation
namespace = ... marks the whole package as being in this namespace, unless
overridden by annotations at the class level (which we don’t need here.) The
elementFormDefault = “QUALIFIED” allows each element to default to the NS of
its containing element. With these in place for the package, the source for the
POJOs in domain is much neater, or could be much neater. See Javadoc for this annotation in the usual
JDK API by selecting the package first.
The following is the Item
POJO in domain: It could be simplified
by removing the @XmlElement annotations, as long as we don’t mind losing
“required” in generated schema. Without @XmlElement, the namespace for milk,
etc., would follow Item’s, which follows the package default set up in
package-info. The @XmlRootElement class annotation explains why <item> is
a global element in the schema, since @XmlRootElement requires <item> to usable
as a root element in XML.
=======================================================================================================
package
com.restbucks.ordering.domain;
import
...
//
This POJO is marked up for XML, but also used as a "domain object"
//
that is, used in server-side implementation code
//
That's OK if we aren't leaking any proprietary information
//
out, i.e., if the object is so plain that it doesn't matter
//
if the outside world sees its structure, and we don't think
//
we'll ever change it.
//
Note that the Order domain objects *are* separate from
//
the OrderRepresentation objects that correspond to the XML
//
XmlRootElement is not needed because we never have JAXB
//
parse XML with item at the root
@XmlRootElement
public
class Item {
@XmlElement(required = true, namespace =
Representation.RESTBUCKS_NAMESPACE)
private Milk milk;
@XmlElement(required = true, namespace =
Representation.RESTBUCKS_NAMESPACE)
private Size size;
@XmlElement(required = true, namespace =
Representation.RESTBUCKS_NAMESPACE)
private Drink drink;
/**
* For JAXB :-(
*/
Item(){}
...
=======================================================================================================
Sample enum from the domain
package: no JAXB annotations needed, because it’s found from the milk field of
Item
=======================================================================================================
package
com.restbucks.ordering.domain;
public enum Size {
SMALL,
MEDIUM,
LARGE,
HUGE
}