Java object serialization of Ajax

Source: Internet
Author: User
Tags add foreach eval expression object model object serialization string version
ajax| objects

If you are using asynchronous JavaScript and XML (Ajax) for Java™web development, your most concern may be to pass data from the server to the client. In the Ajax series for Java Developers, Philip McCarthy describes five ways to serialize Java objects and provides all the information needed to choose the data format and technology that best fits the application. This article will focus on the most concern for many Java Web developers: Generating data for clients.

Most Java developers have applied the model-view-controller (MVC) pattern to their WEB applications. In a traditional WEB application, the view component consists of a JSP or other presentation technology, such as the Velocity template. These presentation components update the user interface by dynamically generating completely new HTML pages, replacing the pages that the user was previously viewing. However, in the case of Java WEB applications using the Ajax UI, JavaScript client code is ultimately responsible for updating what the user sees, based on the data received from the XMLHttpRequest response. From the server's perspective, the view becomes the data representation it sends in response to a client request.

This article focuses on techniques that can be used to generate data-centric views of Java objects. I'll demonstrate the various ways you can turn JavaBeans into XML documents, and discuss the pros and cons of each approach. You'll see why XML isn't always the best way: for simple Ajax requests, it's better to transfer plain text. Finally, I'll introduce JavaScript object annotations (JSON). JSON allows data to be transmitted in the form of serialized JavaScript object graphs, which is extremely easy to handle serialized JavaScript object graphs in client code.

About the example

I'll use a sample application and several use cases to illustrate the technical features and techniques discussed here. The very simple data model shown in Figure 1 can represent the sample use case. This model represents the customer account in the online store. The customer has a collection of previous orders, each containing several items.

Figure 1. A Simple object model

Although XMLHttpRequest has no restrictions on the format used to send data, it is appropriate for most purposes to send only traditional form data, so my discussion is focused on the server's response. The response can also have text-based formatting, but as its name indicates, XMLHttpRequest has the built-in ability to process XML response data. This makes XML the default choice for Ajax responses, so we start with the discussion from XML format.

Generating XML from Java classes

There are many reasons to pass AJAX responses as XML: Each AJAX-enabled browser has a way to navigate XML documents, and there are many server-side technologies that can process XML data. By developing a scenario that describes the type of document to be exchanged, it is easy to define a contract between the Ajax client and the server, and if the server-side architecture is in a service-oriented manner, using XML can also allow non-AJAX clients to use the data that you provide.

I'll consider three ways to generate XML data from Java objects and discuss the pros and cons of each method.

Serialization on its own

First, you can generate XML programmatically from the object graph. This approach can be as simple as implementing the TOXML () method in each JavaBean class. You can then select the appropriate XML API, let each bean provide the element that represents its state, and recursively invoke the object graph on its own members. Obviously, this approach cannot be extended to a large number of classes, because each class needs to write its own XML generation code specifically. On the plus side, this is a simple way to do it, without additional configuration spending or more complex construction process spending, and any JavaBean graph can become an XML document with just a few calls.

Public Element toXml () {

Element elorder = new Element ("order");

Elorder.setattribute ("id", id);

Elorder.setattribute ("Cost", Getformattedcost ());

Element eldate = new Element ("date"). Addcontent (date);

Elorder.addcontent (eldate);

Element elitems = new Element ("items");

for (iterator<item> iter =

Items.iterator (); Iter.hasnext (); ) {

Elitems.addcontent (Iter.next (). TOXML ());

}

Elorder.addcontent (Elitems);

return elorder;

}

Here you can see how simple it is to create elements with JDOM, to use attributes, and to add element content. The ToXml () method of recursively invoking the composite JavaBean is to obtain the Element representation of their child graphs. For example, the contents of the items element are obtained by calling the TOXML () on each Item object that the order is aggregated.

Once all JavaBean have implemented the TOXML () method, it is easy to serialize any object graph into an XML document and return it to the Ajax client, as shown in Listing 2.

Listing 2. Generate an XML response from a JDOM element

public void Doget (HttpServletRequest req, httpservletresponse Res)

Throws Java.io.IOException, Servletexception {

String CustID = Req.getparameter ("username");

Customer customer = GetCustomer (CustID);

Element Responseelem = Customer.toxml ();

Document Responsedoc = new document (Responseelem);

Res.setcontenttype ("Application/xml");

New Xmloutputter (). Output (Responsedoc,res.getwriter ());

}

JDOM again makes the work very simple. You only need to wrap a document outside the XML elements returned by the object graph, and then write the documentation to the servlet response with Xmloutputter. Listing 3 shows the XML example generated in this way, initializing Xmloutputter with JDOM Format.getprettyformat (), which is nicely formatted. In this example, the customer made only one order, containing two items.

<?xml version= "1.0" encoding= "UTF-8"

<customer username= "jimmy66"

<realname>james hyrax</realname>

<orders>

<order id= "o-11123" cost= "$349.98"

<date>08-26-2005</date>

<items>

<item id= "i-55768"

<name>oolong 512MB CF card</name>

<description>512 megabyte Type 1 CompactFlash card.

manufactured by Oolong Industries</description>

<price>$49.99</price>

</item>

<item id= "i-74491"

<name>fujak Superpix72 camera</name>

<description>7.2 Megapixel digital camera featuring six

shooting modes and 3x optical zoom. Silver.</description>

<price>$299.99</price>

</item>

</items

</order>

</orders>

</customer>

Lack of self-serialization

Interestingly, the code in Listing 3 shows one of the main drawbacks of having JavaBean serialize itself into XML. Suppose you want to use this document to represent the customer's order history view. In this case, it is not likely to display a complete description of each item in each historical order, or to tell the customer his or her own name. However, if your application has a ProductSearch class that returns search results as a list of item beans, it may be helpful to include instructions in the XML representation of the item. Also, extra fields on the Item class that represent the current inventory level may be useful information to display in the product search view. However, regardless of whether the current inventory level is related to the current situation (for example, for the customer's order history), the field is serialized from any object graph that contains the Item.

From a design perspective, this is a classic problem of coupling data models with view generation. Each bean can only serialize itself in one way, in the same way that the Ajax interaction ultimately swaps the data they do not need to exchange, making it more difficult for client code to find the information it needs from the document, as well as increasing bandwidth consumption and the client's XML parsing time. Another consequence of this coupling is that the syntax of XML cannot be separated from the Java class. For example, modifying the scenario of a customer document may affect multiple Java classes, causing them to be modified and recompiled.

In recent years, several Java APIs have been developed to simplify the binding process of XML documents to Java object graphs. Most of them provide XML orchestration and disassembly, that is, they can perform bidirectional conversations between Java object diagrams and XML. These frameworks encapsulate all the work of XML processing, which means that the application code only needs to handle ordinary Java classes. They also want to provide useful accessibility features, such as document validation. In general terms, these frameworks take two different forms: code generation and object to XML mapping. I will explain each of these two ways separately.

How code is generated

Frameworks that use code generation include XMLBeans, JAXB, Zeus, and JBind. Castor can also use this technique. The starting point for such a framework is an XML schema that describes the document data type. Using the tools provided by the framework, you can generate Java classes that represent these schema-defined types. Finally, you use these generated classes to write applications that represent your own model data, and to serialize the data into XML through some of the supporting mechanisms provided by the framework.

If your application uses large XML syntax, code generation is a good way to do it. The scalability of writing custom XML serialization code on dozens of classes is eliminated. On the other hand, you no longer need to define your own JavaBean. The Java classes generated by the framework usually conform very well to the structure of XML, so it is difficult to encode them. Also, the generated classes become dumb data containers because they are generally not added to the behavior. In general, there are compromises to be made in the application code to handle the type of scenario generation well. Another drawback is that if you modify the scenario, the generated classes will also be modified, and therefore the code that surrounds them will be affected accordingly.

This type of XML binding framework is most useful when data is disassembled (for example, using XML documents and translating them into Java objects). Unless you have a large data model and are likely to benefit from the generated classes, a code-generated framework can be a great killer for Ajax applications.

How to map

The frameworks for mapping include Castor and Apache Commons betwixt. Mapping is usually a more flexible and lightweight solution than code generation. First, you can write JavaBean as you normally do, including any behavior, and any convenient way you like. Then, at run time, you invoke the introspective choreographer in the frame and generate the XML document based on the type, name, and value of the object member. By defining the mapping file for a class, you can override the default binding policy and make recommendations to the choreographer about how the class is represented in XML.

This approach is a good compromise between scalability and flexibility. You can write Java classes in the way you like, and the choreographer handles XML. Although mapping definition files are simple to write and scalable enough, mapping rules can only change the standard binding behavior, and there is always a residual coupling between the object structure and their XML representation. Eventually, you might have to make a compromise between the Java presentation or the XML format to make the mapping approach work.

Data Binding Summary

Dennis Sosnoski wrote an in-depth article on the subject of the XML data binding API in two aspects of code generation and code mapping. If you want to study this area further, I recommend his wonderful articles on Castor and code generation frameworks.

In short, code generation has lost too much flexibility and convenience, and is not very useful for typical Ajax applications. On the other hand, a mapped framework might work well, but adjust their mapping strategy just right to generate the XML needed from the object.

All XML binding APIs have one major shortcoming of manual serialization techniques: The coupling of models and views. Being limited to an XML representation of a type means that there is always a redundant data transfer on the network. A more serious problem is that the client code does not get it when the situation requires the client code to use a specialized view, so you may struggle to handle the immutable view of the given object graph.

In the traditional WEB application development, the page template system is used to separate the view generation from the controller logic and model data cleanly. This approach can also be helpful in Ajax scenarios.

Any common Purpose page template technology can be used to generate XML that enables AJAX applications to generate any XML response document based on its own data model. The bonus is that templates can be written in a simple, expressive markup language, rather than a line of Java code. Listing 5 is a JSP page that employs a customer bean and represents a custom XML view that is suitable for client code generation order history components.

Listing 4. JSP that generates the order history document

<?xml version= "1.0"?>

<%@ page contenttype= "Application/xml"%>

<%@ taglib uri= "Http://java.sun.com/jsp/jstl/core" prefix= "C"%>

<c:set var= "Cust" value= "${requestscope.customer}"/>

<orderhistory username= "${cust.username}" >

<c:foreach var= "Order" items= "${cust.orders}" >

<order id= "${order.id}" cost= "${order.formattedcost}" >

<date>${order.date}</date>

<items>

<c:foreach var= "Item" items= "${order.items}" >

<item id= "${item.id}" >

<name><c:out value= "${item.name}" Escapexml= "true"/></name>

<price>${item.formattedPrice}</price>

</item>

</c:forEach>

</items>

</order>

</c:forEach>

</orderhistory>

This concise template outputs only the data required by the order History view and does not output irrelevant information (such as a description of the product). Creating custom XML for the product search view should be as simple as this view, which contains the complete description and inventory level of each item.

Problems with templates

On the other hand, now I need to create a new JSP for each of the different views, instead of just organizing the desired object graph and serializing it. From a design standpoint, many people may be disputing that this is a good thing anyway, because it means formally considering the type of document the server is going to generate. And, because I'm now working on the generic template environment, not the XML-specific APIs, it's my responsibility to make sure that tag matching, elements and attributes are in the right order, and that XML entities (such as < or &) are correctly escaped. The core out tag of the JSP makes this work easy, but not all templating technologies provide such a mechanism. Finally, there is no convenient way to verify the correctness of the generated XML documents on the server side, but this is not something to do in a production environment and can be easily handled during development.

No XML response data

So far, all the techniques I've described are generating server responses in the form of XML documents. However, there are some problems with XML. One of them is the delay. Browsers cannot parse XML documents immediately and generate a DOM model, so this reduces the sense of "swiftness" that some Ajax components need, especially when parsing large documents on slower machines. "Live Search" is an example of a search in which the user extracts search results from the server and displays them to the user when they enter a search term. It is important for field search components to respond quickly to input, but at the same time it needs to resolve server responses quickly and consistently.

Latency is an important consideration, but the biggest reason to avoid using XML is poor client DOM APIs. Listing 5 shows the difficulties that you usually have to face when you get a value out of the DOM using a cross-browser-compatible approach.

Listing 5. Navigating XML response documents in JavaScript

Find name of ' s

var orderhistorydoc = Req.responsexml;

var orders = Orderhistorydoc.getelementsbytagname ("Order");

var lastorder = orders[orders.length-1];

var FirstItem = lastorder.getelementsbytagname ("item") [0];

var itemnameelement = Firstitem.firstchild;

var itemnametext = ItemNameElement.firstChild.data;

When there is a gap in the middle of an element, the situation becomes more complex, because the firstchild of each element is often a blank text node. There is now a JavaScript library to ease the hassle of processing XML documents. These libraries include Sarissa and GOOGLE-AJAXSLT, both of which add XPath functionality to most browsers.

ResponseText is especially handy when the server needs to send a very simple value to the client, which avoids bandwidth overhead and processing expenses that are caused by XML. For example, a simple true/false response can be returned by the server as plain text, and can be a comma-separated list of simple names or numbers. However, in general, it is best not to mix XML responses with plain text responses in the same application; Keeping a single data format makes code abstraction and reuse simpler.

ResponseText can also be useful when combined with XML response data. In a scenario where only a single value is extracted from a response document, it is more convenient to "spoof" the XML as a text string rather than treating it as a structured document. For example, listing 6 shows how to use a regular expression to extract the date of the first order from the customer's order history. However, this is actually a gimmick, and generally should not rely on the vocabulary expression of XML documents.

Listing 6. Using regular expressions to handle XMLHttpRequest ResponseText objects

var orderhistorytext = Req.responsetext;

var matches = Orderhistorytext.match (/<date> (. *?) <\/date>/);

var date = matches[1];

In some cases, it is convenient to use responsetext in a real-time manner. Ideally, however, there should be a way to represent complex structured data in a format that allows JavaScript to navigate easily without XML processing expenses. Fortunately, there is a format that does exist.

JavaScript Object Annotations

In fact, most of the JavaScript objects are composed of union arrays, numeric indexed arrays, strings, numbers, or nested sets of these types. Because all types can be declared directly with JavaScript, you can statically define the object graph in a single statement. Listing 7 declares an object using JSON syntax and demonstrates how to access the object. Curly braces represent a union array (that is, an object) whose key-value combinations are separated by commas. The square brackets represent an array of numeric indices.

Listing 7. Declaring a simple object directly in JavaScript with JSON

var band = {

Name: "The Beatles",

Members: [

{

Name: "John",

Instruments: ["Vocals", "Guitar", "Piano"]

},

{

Name: "Paul",

Instruments: ["Vocals", "Bass", "Piano", "Guitar"]

},

{

Name: "George",

Instruments: ["Guitar", "Vocals"]

},

{

Name: "Ringo",

Instruments: ["Drums", "Vocals"]

}

]

};

Interrogate the band object

var musician = band.members[3];

Alert (musician.name

+ "played" + Musician.instruments[0]

+ "with" + band.name);

The advantages and disadvantages of different XML generation techniques also apply to the generation of JSON. And it can be proven that there is a need to reuse the presentation template technology. However, using JSON is more of an idea than passing the serialized object between the application tiers, rather than creating the view of the application state. I'll explain how to create a Tojsonobject () method on a Java class using the Org.json Java API. You can then simply serialize the Jsonobject to JSON. Listing 8 reflects the XML discussed in Listing 1, which shows the tojsonobject () implementation of the Order class.

Listing 8. Tojsonobject () method implementation of order class

Public Jsonobject Tojsonobject () {

Jsonobject json = new Jsonobject ();

Json.put ("id", id);

Json.put ("Cost", Getformattedcost ());

Json.put ("date", date);

Jsonarray jsonitems = new Jsonarray ();

for (iterator<item> iter =

Items.iterator (); Iter.hasnext (); ) {

Jsonitems.put (Iter.next (). Tojsonobject ());

}

Json.put ("Items", jsonitems);

return JSON;

}

As you can see, the Org.json API is very simple. Jsonobject represents a JavaScript object (that is, a federated array) with a different put () method, which accepts a string key and a value that is a primitive type, a string type, or another JSON type. Jsonarray represents an indexed array, so its put () method accepts only one value. Notice that in Listing 8, you create the Jsonitems array, and then attach it to the JSON object using put (), and you can do it in another way by calling Json.accumulate ("items", Iter.next () for each item. Tojsonobject ()); The accumulate () method is similar to put (), except that it adds a value to an array of indexes that are identified by the key.

Listing 9 shows how to serialize the Jsonobject and write it to the servlet response.

Listing 9. To generate a serialized JSON response from Jsonobject

public void Doget (HttpServletRequest req, httpservletresponse Res)

Throws Java.io.IOException, Servletexception {

String CustID = Req.getparameter ("username");

Customer customer = GetCustomer (CustID);

Res.setcontenttype ("Application/x-json");

Res.getwriter (). Print (Customer.tojsonobject ());

}

Can see that it actually did nothing. The Jsonobject's ToString () method, which is implicitly invoked here, does all the work. Note that there is a bit of uncertainty about the Application/x-json content type--it is not conclusive as to what kind of MIME type JSON should belong to when writing this article. However, the current Application/x-json is a reasonable choice. Listing 10 shows a sample response to this servlet code.

Listing 10. JSON representation of the Customer bean


"Orders": [

{

"Items": [

{

"Price": "$49.99",

"description": "Megabyte Type 1 CompactFlash card."

Manufactured by Oolong Industries ",

"Name": "Oolong 512MB CF card",

"id": "i-55768"

},

{

"Price": "$299.99",

"description": "7.2 Megapixel digital camera featuring

Shooting modes and 3x optical zoom. Silver. ",

"Name": "Fujak Superpix72 Camera",

"id": "i-74491"

}

],

"Date": "08-26-2005",

"Cost": "$349.98",

"id": "o-11123"

}

],

"Realname": "James Hyrax",

"username": "jimmy66"

}

The final step in processing is to turn the JSON data into a JavaScript object at the client. This can be done through a simple call to Eval (), which can instantly interpret a string containing a JavaScript expression. Listing 11 turns the JSON response into a JavaScript object graph, and then executes the task in Listing 5 to get the first item's name from the customer's last order.

Listing 11. Evaluate the JSON response

var jsonexpression = "(" + Req.responsetext + ")";

var customer = eval (jsonexpression);

Find name of ' s

var lastorder = customer.orders[customer.orders.length-1];

var name = Lastorder.items[0].name;

Compare listings 11 and 5 to discover the advantages of using JSON for clients. If you are navigating a number of complex server responses on the client in an Ajax project, then JSON may be appropriate for your needs. The combination of JSON and XMLHttpRequest also makes Ajax interactions look more like RPC calls than SOA requests, which can be meaningful for the design of an application. The framework I'm going to look at in the next article is explicitly designed to allow JavaScript code to make remote method calls to server-side objects.

The lack of JSON

JSON also has its drawbacks. Using the JSON approach described here, there is no way to crop the serialization of objects for each request, so unwanted fields may often be sent over the network. In addition, adding the Tojsonobject () method to each JavaBean is not very scalable, although it may be easy to write a generic JavaBean to JSON serializer with introspection and annotations. Finally, if the server-side code is service-oriented and has not been adjusted individually for processing Ajax client requests, XML will be a better choice because of consistent XML support.

Comparison serialization Technology

Now you've seen five different techniques for transferring Java state to Ajax clients. I discussed the manual encoding of XML serialization, XML binding through code generation, XML binding through mapping mechanisms, template-based XML generation, and serialization by hand encoding to JSON. Each of these technologies has its own advantages and disadvantages that apply to different application architectures.

To summarize the advantages and disadvantages of each approach, table 1 makes a rough score from six aspects:

Scalability

Describes the ease with which technology adapts to a large number of data types. Does the coding and configuration effort increase for each additional type?

Easy Integration

Evaluate the simplicity of integrating technology into a project. Do you need a more complex build process? Have you increased the complexity of your deployment?

Java class API

Describes how easy it is to handle server-side Java objects in a specified manner. Is it possible to write ordinary beans or have to deal with clumsy document representations?

control of the output

Describes the precise extent to which the serialization representation of a class is controlled.

View Flexibility

Evaluates whether different, customized data serialization can be created from the same set of objects.

Client data access

Describes the ease with which JavaScript code handles server response data.

Table 1. Relative value of data generation technology

Write your own XML XML bindings generated by code XML Binding by mapping Page Template XML Hand-coded JSON serialization
Scalability Poor Good So so So so Poor
Easy integration Good Poor So so So so Good
Java class API Good Poor Good Good Good
Control of the output Good Good So so Good Good
View flexibility Poor Poor Poor Good Poor
Client data access Poor Poor Poor So so Good

Conclusion

The data in table 1 does not indicate that a particular serialization technique is better than other techniques. After all, the relative importance of the six criteria depends on the specifics of the project. For example, if you want to work with hundreds of types of data, and you want scalability, then code generation is probably the best choice. If you need to generate several different views for the same data model, you should use a page template. If you're working on a small project and want to reduce the number of JavaScript code you need to write, consider JSON.

<

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.