Devsphere Mapping Framework provides an application programming interface (API) that allows you to map objects to HTML forms, XML documents and property text streams. The mappings are bi-directional. You can fill the properties of a bean object with the HTTP request parameters whose values were gathered using an HTML form. You can also set the default values of a pure HTML form to the data contained in a bean object. A bean object can be converted to a text / XML document and vice-versa.
Devsphere Mapping Framework
- supports an application model that makes a clean separation between bean processing, form generation and data handling. This is similar to the MVC model.
- extends the JavaBeans model (without altering it) with concepts specific to form processing, such as optional properties, default values and error messages.
- brings object oriented features, such as inheritance, containment and aggregation into the form processing domain.
- allows you to build easily internationalized Web applications. The I18N support exists in the application model and is extended by the framework's API.
Devsphere Mapping Framework
- frees Web Application Developers of the routine tasks (such as form data handling, user error handling and dynamic form generation) and let them focus on the business logic (bean processing).
- is easy to use and reduces significantly the development time. Existent beans and HTML forms don't need any changes. The only requirement is the use of the same names for bean properties and form elements.
- reduces the maintenance costs. The application model separates the components of the applications in five categories: data beans, bean resources, forms, handlers and processors.
- maps beans to XML and text simplifying the building of software that needs messaging (such as B2B applications) and XML/text-based persistence (such as Web-based administration utilities).
Devsphere Mapping Framework
- splits the mapping errors in two categories: user errors (like "missing data" and "number format error") and application errors. For example, an application error may occur when there are no form elements with the name of a bean property. In this case, the bean property cannot be mapped. The "missing form element" error would be inserted at the beginning of the HTML form that is sent through the servlet's output stream. To correct the error, the developer would have to edit the HTML file and add the form element.
- reloads the cached HTML forms after they are modified. This avoids the restarting of the application and is much faster than recompiling a JSP page.
- includes an extensible logging mechanism which provides loggers that wrap print streams and servlet contexts. You may define new loggers that suit the needs of your application.
Devsphere Mapping Framework
- is very fast and doesn't need too much memory. For HTML parsing, it uses a custom parser highly optimized for forms. Pure HTML files can be parsed only once and cached in memory. Of course, you may control which forms are cached and which of them aren't. For XML parsing, the framework uses the SAX API.
- may run in any servlet engine / application server based on the Servlets 2.x API using any JDK/JRE version (except the old JDK 1.0). If the servlet engine supports Java Server Pages, the JSPs can take full advantage of the framework's API.
- may also run outside of a servlet engine / application server, in the absence of the Servlet API. For example, a standalone application that does offline processing could use the framework to convert text / XML documents to bean objects.
A data bean is a JavaBean component used as data model. This documentation uses frequently the term data bean to refer to the bean class. The term bean object is used for the instances of the bean class.
The bean properties are entities that participate to the mapping process. They are usually the fields of the data bean. However, this isn't a requirement since the get & set methods of the data bean define the bean properties. The mapping utilities use the JavaBeans' introspection API to get the names and the types of the properties of a data bean.
An optional property is a bean property that cannot generate "missing data" errors. If none of the parameters can be mapped to an optional property, no error is signaled and the optional property is set to its default value.
The bean resources are optional information useful to the mapping process, such as default values and error messages. You can define a resource bundle for each data bean and you may localize it to different languages.
The parameters are the entities that are mapped to the bean properties. Examples of parameters include HTTP request parameters, name-value pairs encoded as plain text, and XML elements containing data. Each parameter has a name and a value. A parameter set is a group of parameters that can be mapped to one or more bean objects.
The bean properties are mapped to the entities called elements. Examples of elements include HTML form elements (<INPUT>, <SELECT> and <TEXTAREA>), name-value pairs encoded as plain text and XML elements.
The elements exist within documents. Examples of documents include HTML forms, XML documents and property text files. One or more bean objects can be mapped to a document.
A mapping error is a non-fatal error that occurs during the mapping process. The mapping errors can be application errors or user errors. An application error signals a problem that has to be corrected by the application developer and may occur, for example, when an exception is thrown by a setter or getter method of a bean property. A user error occurs, for example, when the user doesn't fill a non-optional form element. The mapping process isn't stopped by a mapping error. The mapping errors can be logged and/or shown to the user whether they are user or application errors. The fatal errors, such as IOException, interrupt the mapping process and the exception is thrown by the mapping utility.
There are two types of mapping: "to-bean" and "bean-to". A to-bean mapping takes a set of parameters and stores their values to the properties of a bean object. A bean-to mapping stores the values of the bean properties to the elements of a document. The association between bean properties and parameters / elements is based on their names.
A mapping utility is a Java method that maps a parameter set to a bean object or maps a bean object to a document. The framework provides six mapping utilities: FormUtils.formToBean(), FormUtils.beanToForm(), TextUtils.textToBean(), TextUtils.beanToText(), XMLUtils.xmlToBean() and XMLUtils.beanToXML().
The properties of the data beans can be
- strings (String) or string arrays (String)
- primitives (boolean, int, float, etc) or primitive arrays (boolean, int, float, etc)
- primitive wrappers (Boolean, Integer, Float, etc) or wrapper arrays (Boolean, Integer, Float, etc)
- BigInteger, BigDecimal, BigInteger, or BigDecimal
- data beans or arrays of data beans
The mapping utilities separate the properties in four categories:
- standard properties (strings, primitives, primitive wrappers, BigInteger and BigDecimal)
- standard indexed properties (string arrays, primitive arrays, wrapper arrays, BigInteger and BigDecimal)
- data beans
- arrays of data beans
Ideally, the order in which the parameters are mapped to the properties or the properties are mapped to the elements should not matter. Sometimes, however, you want to determine the processing order of the bean properties. For example, you may have to do some operations in a property's setter that depend on the value of another property. In this case, the former should be processed after the latter.
The bean properties are mapped / processed in an order which can be controlled. The properties that are inherited from the bean's superclass are processed first. After that, the mapping utilities process the bean's properties.
By default, the properties defined by a bean are processed in the order of their descriptors that are obtained using the Introspector utility class of the JavaBeans API. You could control this order by defining a BeanInfo class for each bean. (See the JavaBeans specification for details.) If the BeanInfo class isn't defined, you cannot relay on the default property order.
Anyway, it isn't worth coding a BeanInfo class just to define the processing order. Therefore, the mapping framework provides a much easier solution. You can define the processing order as a string array containing the names of the properties. This array is stored as a bean resource and it shouldn't contain the names of the inherited properties. The bean resources of the superclasses can define the processing order of the inherited properties. One of the sections of the next chapter is dedicated to the bean resources and shows you how to code the processing order array.
A data bean may extend another data bean. The mapping is applied first on the properties of the superclass and then on the properties of the bean class.
If you override the getter or the setter of a property, you must be aware that the inherited properties are processed first. In other words, the access methods of the inherited properties are called before the access methods of the new properties.
A data bean can contain other data beans or even arrays of data beans. Unlike standard properties (strings, primitives, etc) which are usually associated with a parameter / element, the contained beans aren't associated with any parameters / elements. Instead, the mapping process is applied to the contained beans in a recursive manner. Suppose a data bean has a property called subBean whose type is a data bean too. A property called prop of subBean could be associated with a parameter / element called subBean.prop. If subBean has its own contained bean, say subSubBean, then a property of the latter, say anotherProp, could be associated with a parameter / element called subBean.subSubBean.anotherProp and so on.
The to-bean mapping creates the instances of the contained beans and maps the parameters to their properties. The bean-to mapping maps the properties of the contained bean objects to the elements. This process is similar to object serialization. However, since the data is mapped to the documents (HTML forms, XML or plain text) it may be either impossible or inefficient to keep the references between objects. Therefore, the bean-to mapping does not allow multiple references to a contained bean object. In other words, a single call to a mapping utility may not map the properties of the same bean object to multiple groups of elements contained by the same document. The storing of a bean object multiple times within the same document wouldn't make sense anyway.
A bean may not be contained directly or indirectly by its own class or by one of its superclasses. If a bean class B defines/inherits a contained bean property whose type is C then B and C must be different classes and C may not be a subclass of B. In addition, none of the properties of C may have the type B or a subclass of B, none of the properties of the properties of C may have the type B or a subclass of B, and so on.
A parameter may have more than one value. Such a parameter can be mapped to an indexed standard property (string array, primitive array, etc). An indexed standard property can be mapped to a group of elements that have the same name.
A data bean may contain an array of data beans. Suppose, there is a contained bean array called subBeanArray and its elements have a standard property called prop. Then subBeanArray[i].prop will be associated to the parameters / elements named subBeanArray.i.prop. The length of the bean array could be associated to a parameter / element called subBeanArray.length or it could be determined in another way depending on the nature of the document.
It is possible to map a parameter set / document to one or more data beans. However, the mapping utilities can process one bean object at a time, so you'll have to call them for each bean. You'll probably want to divide the parameters / elements into partitions and associate each bean to a single partition. It is possible to do this by starting the names of the parameters and elements with a prefix followed by dot. The names of the parameters / elements will look like this: prefix.prop, prefix.subBean.prop, prefix.subBean.subSubBean.anotherProp, etc.
The aggregation of data beans is possible when they are mapped to HTML forms or property text files. An XML document can be mapped only to a single bean.
The formToBean() method of FormUtils fills the properties of a bean with the values of the request parameters that are provided as a FormData instance. Usually, this is a ServletFormData object that wraps an instance of javax.servlet.http.HttpServletRequest.
The formToBean() method is similar to the <jsp:setProperty> tag of JSP, though it offers many advantages:
- formToBean() handles all possible errors, including "missing data" and "number format error". All errors are collected in a hashtable. The <jsp:setProperty> tag may throw any time a NumberFormatException letting the bean in an inconsistent state (some of the properties were set and the others weren't).
- formToBean() stores default values to the properties whose associated request parameters were missing. The <jsp:setProperty> tag does nothing if a parameter is missing.
- formToBean() makes a distinction between optional properties and non-optional properties. The <jsp:setProperty> tag treats all properties as optional properties.
- formToBean() supports contained beans and arrays of beans (the mapping process is recursive). The <jsp:setProperty> tag supports neither contained beans nor bean arrays.
- formToBean() allows you to control the processing order of the bean properties.
For the mach more complex inverse mapping (beans to forms), there is no support in JSP (and this is right). The FormUtils class has a getTemplate() method that accepts as parameter a string, a file, a URL, an input stream or a reader. It parses its content, identifies the form tags (<FORM>, <INPUT>, <TEXTAREA>, <SELECT> and <OPTION>) and creates a FormTemplate instance. This object is a factory of FormDocument instances. Each form document returned by the getDocument() method of FormTemplate is a new object, but all documents share the strings that maintain the HTML content of the parsed form.
The beanToForm() method of FormUtils takes a bean object, an optional hashtable containing the mapping errors returned by formToBean() and a form document. The default values of the form elements are set to the values of the bean properties. The error messages are inserted within the form document. After that, the content of the document may be sent through an output stream or through a writer using the send() method of FormDocument.
The beanToText() and textToBean() methods of TextUtils convert bean objects to property text files and vice-versa. These files contain key-value pairs and use the format of java.util.Properties. The error messages are stored as comments.
The beanToXML() and xmlToBean() methods of XMLUtils convert bean objects to XML and vice-versa. An XML document contains <xmlbean> as the root element, <data> elements for standard properties, <darray> elements for standard indexed properties, <bean> elements for contained beans and <barray> elements for bean arrays. The <value> and <error> elements are used for primitive values and error messages.
All mapping utilities accept an optional Locale parameter. It is used to load the bean resources that contain default values and error messages. You may have application specific resources within those resource bundles, which can be obtained using the getBeanResources() method of HandlerUtils.
Some of the mapping utilities accept an encoding parameter. This is the ID of a character encoding. The CharacterEncoding class defines the IDs.
The mapping utilities can take an optional AbstractLogger parameter, which is an abstract class that declares methods for logging messages and exceptions. The ServletLogger class implements the methods of the AbstractLogger class wrapping a javax.servlet.ServletContext. The PrintLogger wraps a java.io.PrintStream. The CompoundLogger redirects the logging operations to two other loggers.
The next chapter presents an application model and describes the components: data beans, forms, bean resources, handlers and processors. It also gives more information about the framework's features.
Later chapters give implementation details about the mapping between JavaBeans and
Another chapter exemplifies the building of the five types of components: data beans, forms, bean resources, handlers and processors. Then, it shows an equivalent example that doesn't use the framework and compares the two solutions. It also explains the advantages of using bean-independent servlets.
The framework may also be used to