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 package domain we have a file
package-info.java to contain package annotations to set defaults for the whole
package. Note that OrderRepresentation is not in
package domain, so it is not helped by this setup, and has no package-info.java
in its own package. Because of having no package defaults in place, we need to
specify the namespace over and over for OrderRepresentation,
as you see above. 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” if validated. 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
=======================================================================================================
package com.restbucks.ordering.domain;
public enum Size {
SMALL,
MEDIUM,
LARGE,
HUGE
}