CS 639, Class 21
pa3: questions?
pa3 discussion: see SimpleSVG.java for DOM generation with namespace in use. This is also in Test2.java. Or you can use POJOs and JAXB—see EndToEndTest.java in orderService for order generation from POJOs.
Last time: orderService services, XSD for orderService, XML simpleTypes
More on ref=
ref=”tns:item”There is a new element attribute form for item within <order>’s
type: Since <item> is defined at
top level, the <item> child of <order> refers to that declaration
rather than repeating it here. So it can
be a root element of a document or a child element of <order> in the
document. This style of schema definition is fairly common in practice. For one
thing, such schemas can work properly even without the elementFormDefault
being “qualified” (if all elements are defined at top level) since the
differences between qualified and unqualified apply only to elements declared
below the top level. For an example done both ways, see http://www.w3schools.com/schema/schema_example.asp.
Also, po.xsd in the XML Schema
Primer (this doc is also linked from the class web page). The schema of
schemas says that the ref’s attribute value is of type QName,
so it can point out of the schema’s namespace into another namespace. That
brings us into the territory of multiple schemas, which we have been deferring.
Other simpleType: see Harold,
XML Bible, XML Schema chapter (linked)
<xsd:simpleType name="phonoYear'>
<xsd:restriction
base="xsd:gYear">
<xsd:minInclusive value="1877"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:element
name="year" type="phonoYear"/>
Patterns (Regular
Expressions)
example from Primer: SKUType: 3 digits, hyphen, 2 upper case letters, like 213-UB
<xsd:simpleType
name="SKU">
<xsd:restriction base="xsd:string">
<xsd:pattern
value="\d\d\d-[A-Z][A-Z]” />
</xsd:restriction>
<xsd:simpleType
• the patterns use the Perl style of regular expressions (also
used in JavaScript) (some details different from Java reg. exprs)
• the above pattern could also be represented by [0-9][0-9][0-9]-[A-Z][A-Z] and be readable by more people.
But is this useful for REST messages with JAX-RS? or .NET?
JAXB can recognize the first example and create enums for them:
package com.restbucks.ordering.domain;
public enum Size {
SMALL,
MEDIUM,
LARGE
}
but that’s about it. Most restrictions have to
be handled by validation, as outlined earlier.
We saw that REST services use XML messages to express resource state.
--for example, a whole order, with several order details
Standard specification of XML format is XML Schema, available via WADL, itself available at application.wadl off the base URL.
(This is only true for recent Jersey versions. Last year Jersey created a WADL file with no schema linkage)
Surprise from last time: orderService doesn’t hue to its XSD:
--accepts child elements out of order
--accepts orders without required child elements
--this “lax” behavior is traceable to its use of JAXB without validation.
--we could turn on validation with JAXB and start rejecting these XSD-invalid requests
--But the right amount of laxness is good for business, at least with products as cheap as cups of coffee.
JAXB
Let’s look at JAXB in more detail. The big picture, from overview at Sun:
|
|
|
marshal = serialize
unmarshal = deserialize
“marshal” from the English word to arrange troops in order: here we arrange the data in order for transmission over the network (typically)
XML schema --> POJO classes: ant gen-pojos-from-schema
We can also go from POJO classes to XML Schema. ant gen-schema-from-pojos
For the marshalling and unmarshalling, we depend on Jersey, client or server-side support.
Client-side: Echo and Todo POJOs (not covered in class)
from sendPOJOreceivePOJO in Test2.java of firstRest: create POJO, send off with Jersey call, get back an Echo POJO
Todo todo = new Todo("2", "get this
working now!");
// Do it naked--just get the content
object
Echo responsePOJO = service.path("rest").path("hello")
.type(MediaType.TEXT_XML).accept(MediaType.TEXT_XML)
.post(Echo.class, todo);
// or the “wrapped” version, so you can get headers, etc. as well as the XML content
client-side in orderService project’s EndToEnd.java functional test. Set up an object graph for an order, send it off using Jersey. Jersey serializes it with JAXB. Response is deserialized by JAXB used by Jersey in getEntity call. Here orderResource is a WebResource.
Item item = new Item(Size.LARGE, Milk.SEMI, Drink.CAPPUCCINO);
List<Item> items = new
ArrayList<Item>();
items.add(item);
CustomerOrder order = new
CustomerOrder(Location.TAKEAWAY, items);
ClientResponse response =
orderResource.accept(XML_MEDIA_TYPE).type(XML_MEDIA_TYPE)
.post(ClientResponse.class, order);
OrderRepresentation orderRep = response.getEntity(OrderRepresentation.class);
Server-side: Naked, from firstRest2: just return a POJO, let Jersey use JAXB on it:
@GET
@Produces({MediaType.APPLICATION_XML,
MediaType.APPLICATION_JSON})
public Todo getTodo() {
Todo todo = TodoDao.instance.getModel().get(id); // create Todo object
if(todo==null)
throw new RuntimeException("Get: Todo
with " + id + " not
found");
return todo;
}
Server-side: Wrapped into Response object, from orderService: use Response object with method chain.
@GET
@Path("/{orderId}")
@Produces("application/xml")
public Response getOrder(@PathParam("orderId") String id) {
try {
OrderRepresentation
responseRepresentation = new ReadOrderActivity().retrieveById(id);
return Response.ok().entity(responseRepresentation).build();
} catch(NoSuchOrderException nsoe) {
return Response.status(Status.NOT_FOUND).build();
} catch (Exception ex)
{
return Response.serverError().build();
}
}
Why Order and OrderRepresentation? Order is in the domain package, the “business objects” or “domain objects” that are used in the “business code” of the service, that is the inner workings of the site. There is a concern that proprietary information might leak out if the important business objects are automatically serialized by JAXB and sent out. So the software builds a little wall between the domain object Order and the representation object OrderRepresentation, allowing serialization only of the representation and keeping its class in another package to show it’s not a domain object.
The more minor domain objects like Milk are less concerning, and are allowed a dual role of domain object and representation object. The in-between Item object could go either way, but here is allowed a dual role. Note that annotations have no affect on the code execution of the domain objects.
Online docs:
· Vogel’s short JAXB tutorial linked from his firstRest tutorial (now linked separately from the class web page too)
· No middle-level tutorial that I could find
· Comprehensive user documentation at jaxb.java.net
orderService has two order-related POJOs:
app works with Orders, then converts to/from OrderRepresentation for external communication
That way, Order can contain proprietary features we don’t want blasted around the network.
In the firstRest tutorial code, the JAXB POJO classes had minimal annotations. The one that can’t be defaulted away is the XMLRootElement marking a possible root element object in conversion to POJOs. So Todo.java has @XmlRootElement as a class annotation. But note that the this setup does not use namespaces, whereas orderService does.
orderService serves out the XSD that corresponds to OrderRepresentation. So a client can use it to gen up an OrderRepresentation POJO very easily. Of course it won’t have all the code that orderService may put in this class.
Ex: OrderRepresentation constructor from Order and id, and getOrder(), that creates an Order from this OrderRepresentation.
Front side of
handout: orderService POJO OrderRepresentation.java (done the hard way without
package defaults)
Back side: POJO
Item.java, simpler because it rides on package defaults set up in
package-info.java
In the orderService POJOs, we see annotations on each child element, the opposite approach to firstRest. It works, but we wonder if it’s necessary. Note that orderService is using a namespace, while firstRest didn’t use one. With the help of package defaults, POJOs can be simplified down to the level we saw in firstRest, where only @XmlRootElement is used, if we don’t mind all optional child elements in the corresponding schema.
At least, Item.java is using only two annotations in the POJO class, in the case of proper package-info.java (and we could drop the unneeded @XmlRootElement)
@XmlRootElement: so JAXB can match root element in deserialization (here with properly matching NS). On the outbound side, the name=xxx specifies the root element name, which can be different from the default of the slightly-modified class name.
name=... local name of XML element
namespace= namespace for XML element
Recall how Jersey finds the annotation-marked-up classes via an init-param in web.xml that specifies the packages to look in.
@XmlElement, so this field will correspond to a child element or elements in the case of the List
name=... local name of XML element
namespace= namespace for XML element
required= true or false
(also defaultValue, nillable, type, less often used)
The XmlElement doc says that the namespace defaults to none, unless the package has annotation @XmlSchema (elementFormDefault=”QUALIFIED”), in which case it defaults to its containing element’s namespace, a big help in minimizing annotations.
These annotations have Javadoc in the JDK API docs. An annotation is a type, as is a class and an interface—they all get pages in the API.
Note the annotation @XmlAccessorType(XmlAccessType.FIELD).
Without this annotation, the AccessType is PUBLIC_MEMBER, which requires a
getter/setter pair to qualify a property for inclusion in the generated XML in
the absence of its own @XmlElement annotation.
With this FIELD annotation, fields will cause child elements in the
generated XML, without individual @XmlElement annotation.
Thus there are two recommended ways
to go with fields of a POJO, in a class whose package has the package
annotation as discussed above (or no namespace to worry about):
--Use @XmlElement on each field, so
required fields vs. optional ones are clear (don’t need namespace=… here,
though it doesn’t hurt)
--Use
@XmlAccessorType(XmlAccessType.FIELD) on the class and only use @XmlElement on
required fields.
Additionally, in either case, use
@XmlRootElement for root elements of XML that need deserialization, and/or XML
root name specification
We see the extreme case in
firstRest’s Todo of no @XmlElement and no @XmlAccessorType(XmlAccessType.FIELD)
annotations, so all these fields will be optional in the schema and under
validation. The AccessType is
PUBLIC_MEMBER, so JAXB looks for getter/setter pairs and finds three here, for
id, summary, and description properties, so these are the child elements. The root element name todo is derived from
the class name Todo.
Note: it is possible to ask for an <items> wrapper element too. See bookList in Vogel’s JAXB tutorial.