Thứ Hai, 9 tháng 12, 2013

Dozer: Mapping JAXB Objects to Business/Domain Objects

Dozer is an open source (Apache 2 license) "Java Bean to Java Bean mapper that recursively copies data from one object to another." As this description from its main web page states, it is used to map two JavaBeans instances for automatic data copying between the instances. Although these can be any of the many types of JavaBeans instances, I will focus this post on using Dozer to map JAXB-generated objects to "business data objects" (sometimes referred to as "domain objects").

In Java applications making use of the Java Architecture for XML Binding (JAXB), it is very common for developers to write specific business or domain objects for use in the application itself and only use the JAXB-generated objects for reading (unmarshalling) and writing (marshalling) XML. Although using the JAXB-generated objects themselves as the business/domain objects has some appeal (DRY), there are disadvantages to this approach. JAXB-generated classes do not have toString(), equals(Object), or hashCode() implementations, making these generated classes unsuitable for use in many types of collections, unsuitable for comparison other than identity comparison, and unsuitable for easily logging their contents. Manually editing these generated classes after their generation is tedious and is not conducive to regeneration of the JAXB classes again when even slight changes might be made to the source XSD.

Although JAXB2 Basics can be used to ensure that JAXB-generated classes have some of the common methods needs for use in collections, use in comparisons, and for logging of their contents, a potentially even bigger issue with using JAXB-generated classes as domain/business objects is the tight coupling of business logic to XSD this entails. A schema change in an XSD (such as for version update) typically leads to a different package structure for classes generated from that XSD via JAXB. The different package structure then forces all code that imports those JAXB-generated classes to change their import statements. Content changes to the XSD can have even more dramatic impacts, affecting get/set methods on the JAXB classes that would be strewn throughout the application if the JAXB classes are used for domain/business objects.

Assuming that one decides to not use JAXB-generated classes as business/domain classes, there are multiple ways to map the generated JAXB classes to the classes defining the business/domain objects via a "mapping layer" described in code or configuration. To demonstrate two code-based mapping layer implementations and to demonstrate a Dozer-based mapping layer, I introduce some simple examples of JAXB-generated classes and custom built business/domain classes.

The first part of the example for this post is the XSD from which JAXB'x xjc will be instructed to general classes for marshalling to XML described by that XSD or unmarshalling from XML described by that XSD. The XSD, which is shown next, defines a Person element which can have nested MailingAddress and ResidentialAddress elements and two String attributes for first and last names. Note also that the main namespace is http://marxsoftware.blogspot.com/, which JAXB will use to determine the Java package hierarchy for classes generated from this XSD.

Person.xsd

<?xml version="1.0"?>
<xs:schema version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:marx="http://marxsoftware.blogspot.com/"
targetNamespace="http://marxsoftware.blogspot.com/"
elementFormDefault="qualified">

<xs:element name="Person" type="marx:PersonType" />

<xs:complexType name="PersonType">
<xs:sequence>
<xs:element name="MailingAddress" type="marx:AddressType" />
<xs:element name="ResidentialAddress" type="marx:AddressType" minOccurs="0" />
</xs:sequence>
<xs:attribute name="firstName" type="xs:string" />
<xs:attribute name="lastName" type="xs:string" />
</xs:complexType>

<xs:complexType name="AddressType">
<xs:attribute name="streetAddress1" type="xs:string" use="required" />
<xs:attribute name="streetAddress2" type="xs:string" use="optional" />
<xs:attribute name="city" type="xs:string" use="required" />
<xs:attribute name="state" type="xs:string" use="required" />
<xs:attribute name="zipcode" type="xs:string" use="required" />
</xs:complexType>

</xs:schema>

When xjc (the JAXB compiler delivered with Oracle's JDK) is executed against the above XSD, the following four classes are generated in the directory com/blogspot/marxsoftware (derived from the XSD's namespace): AddressType.java, PersonType.java, ObjectFactory.java, and package-info.java.

The next two code listings are of the two main classes of interest (PersonType.java and AddressType.java) generated by JAXB. The primary purpose of showing them here is as a reminder that they lack methods we often need our business/domain classes to have.

JAXB-generated PersonType.java

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2013.12.03 at 11:44:32 PM MST
//


package com.blogspot.marxsoftware;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;


/**
* <p>Java class for PersonType complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="PersonType">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="MailingAddress" type="{http://marxsoftware.blogspot.com/}AddressType"/>
* <element name="ResidentialAddress" type="{http://marxsoftware.blogspot.com/}AddressType" minOccurs="0"/>
* </sequence>
* <attribute name="firstName" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="lastName" type="{http://www.w3.org/2001/XMLSchema}string" />
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "PersonType", propOrder = {
"mailingAddress",
"residentialAddress"
})
public class PersonType {

@XmlElement(name = "MailingAddress", required = true)
protected AddressType mailingAddress;
@XmlElement(name = "ResidentialAddress")
protected AddressType residentialAddress;
@XmlAttribute(name = "firstName")
protected String firstName;
@XmlAttribute(name = "lastName")
protected String lastName;

/**
* Gets the value of the mailingAddress property.
*
* @return
* possible object is
* {@link AddressType }
*
*/
public AddressType getMailingAddress() {
return mailingAddress;
}

/**
* Sets the value of the mailingAddress property.
*
* @param value
* allowed object is
* {@link AddressType }
*
*/
public void setMailingAddress(AddressType value) {
this.mailingAddress = value;
}

/**
* Gets the value of the residentialAddress property.
*
* @return
* possible object is
* {@link AddressType }
*
*/
public AddressType getResidentialAddress() {
return residentialAddress;
}

/**
* Sets the value of the residentialAddress property.
*
* @param value
* allowed object is
* {@link AddressType }
*
*/
public void setResidentialAddress(AddressType value) {
this.residentialAddress = value;
}

/**
* Gets the value of the firstName property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getFirstName() {
return firstName;
}

/**
* Sets the value of the firstName property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setFirstName(String value) {
this.firstName = value;
}

/**
* Gets the value of the lastName property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getLastName() {
return lastName;
}

/**
* Sets the value of the lastName property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setLastName(String value) {
this.lastName = value;
}

}
JAXB-generated AddressType.java

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2013.12.03 at 11:44:32 PM MST
//


package com.blogspot.marxsoftware;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;


/**
* <p>Java class for AddressType complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="AddressType">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <attribute name="streetAddress1" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="streetAddress2" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="city" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="state" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="zipcode" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "AddressType")
public class AddressType {

@XmlAttribute(name = "streetAddress1", required = true)
protected String streetAddress1;
@XmlAttribute(name = "streetAddress2")
protected String streetAddress2;
@XmlAttribute(name = "city", required = true)
protected String city;
@XmlAttribute(name = "state", required = true)
protected String state;
@XmlAttribute(name = "zipcode", required = true)
protected String zipcode;

/**
* Gets the value of the streetAddress1 property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getStreetAddress1() {
return streetAddress1;
}

/**
* Sets the value of the streetAddress1 property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setStreetAddress1(String value) {
this.streetAddress1 = value;
}

/**
* Gets the value of the streetAddress2 property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getStreetAddress2() {
return streetAddress2;
}

/**
* Sets the value of the streetAddress2 property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setStreetAddress2(String value) {
this.streetAddress2 = value;
}

/**
* Gets the value of the city property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getCity() {
return city;
}

/**
* Sets the value of the city property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setCity(String value) {
this.city = value;
}

/**
* Gets the value of the state property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getState() {
return state;
}

/**
* Sets the value of the state property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setState(String value) {
this.state = value;
}

/**
* Gets the value of the zipcode property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getZipcode() {
return zipcode;
}

/**
* Sets the value of the zipcode property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setZipcode(String value) {
this.zipcode = value;
}

}

A common and straightforward tactic for copying data between the JAXB-generated objects and the custom-written business/domain objects is to use the "get" methods of one object and pass its return value to the "set" method of the other object. For example, in the process of unmarshalling/reading XML into the application, the results of "get" methods called on the JAXB-generated objects can be passed to the "set" methods of the business/domain objects. In the opposite direction, marshalling/writing XML can be easily accomplished by passing the result of "get" methods on the domain/business objects to corresponding "set" methods of the JAXB-generated objects. The next code listing is for PersonCoverter.java and illustrates one implementation of this approach.

PersonConverter.java

package dustin.examples.dozerdemo;

import com.blogspot.marxsoftware.AddressType;
import com.blogspot.marxsoftware.ObjectFactory;
import com.blogspot.marxsoftware.PersonType;
import dustin.examples.Address;
import dustin.examples.Person;

/**
* Static functions for converting between JAXB-generated objects and domain
* objects.
*
* @author Dustin
*/
public class PersonConverter
{
/**
* Extract business object {@link dustin.examples.Person} from the JAXB
* generated object {@link com.blogspot.marxsoftware.PersonType}.
*
* @param personType JAXB-generated {@link com.blogspot.marxsoftware.PersonType}
* from which to extract {@link dustin.examples.Person} object.
* @return Instance of {@link dustin.examples.Person} based on the provided
* {@link com.blogspot.marxsoftware.PersonType}.
*/
public static Person extractPersonFromPersonType(final PersonType personType)
{
final String lastName = personType.getLastName();
final String firstName = personType.getFirstName();
final Address residentialAddress =
extractAddressFromAddressType(personType.getResidentialAddress());
final Address mailingAddress =
extractAddressFromAddressType(personType.getMailingAddress());
return new Person(lastName, firstName, residentialAddress, mailingAddress);
}

/**
* Extract business object {@link dustin.examples.Address} from the JAXB
* generated object {@link com.blogspot.marxsoftware.AddressType}.
*
* @param addressType JAXB-generated {@link com.blogspot.marxsoftware.AddressType}
* from which to extract {@link dustin.examples.Address} object.
* @return Instance of {@link dustin.examples.Address} based on the provided
* {@link com.blogspot.marxsoftware.AddressType}.
*/
public static Address extractAddressFromAddressType(final AddressType addressType)
{
return new Address(
addressType.getStreetAddress1(), addressType.getStreetAddress2(),
addressType.getCity(), addressType.getState(), addressType.getZipcode());
}

/**
* Extract an instance of {@link com.blogspot.marxsoftware.PersonType} from
* an instance of {@link dustin.examples.Person}.
*
* @param person Instance of {@link dustin.examples.Person} from which
* instance of JAXB-generated {@link com.blogspot.marxsoftware.PersonType}
* is desired.
* @return Instance of {@link com.blogspot.marxsoftware.PersonType} based on
* provided instance of {@link dustin.examples.Person}.
*/
public static PersonType extractPersonTypeFromPerson(final Person person)
{
final ObjectFactory objectFactory = new ObjectFactory();
final AddressType residentialAddressType =
extractAddressTypeFromAddress(person.getResidentialAddress());
final AddressType mailingAddressType =
extractAddressTypeFromAddress(person.getMailingAddress());

final PersonType personType = objectFactory.createPersonType();
personType.setLastName(person.getLastName());
personType.setFirstName(person.getFirstName());
personType.setResidentialAddress(residentialAddressType);
personType.setMailingAddress(mailingAddressType);

return personType;
}

/**
* Extract an instance of {@link com.blogspot.marxsoftware.AddressType} from
* an instance of {@link dustin.examples.Address}.
*
* @param address Instance of {@link dustin.examples.Address} from which
* instance of JAXB-generated {@link com.blogspot.marxsoftware.AddressType}
* is desired.
* @return Instance of {@link com.blogspot.marxsoftware.AddressType} based on
* provided instance of {@link dustin.examples.Address}.
*/
public static AddressType extractAddressTypeFromAddress(final Address address)
{
final ObjectFactory objectFactory = new ObjectFactory();
final AddressType addressType = objectFactory.createAddressType();
addressType.setStreetAddress1(address.getStreetAddress1());
addressType.setStreetAddress2(address.getStreetAddress2());
addressType.setCity(address.getMunicipality());
addressType.setState(address.getState());
addressType.setZipcode(address.getZipCode());
return addressType;
}
}

The last code listing demonstrated a common third-party class approach to copying data in both directions between the JAXB-generated objects and the domain/business objects. Another approach is to build this copying capability into the domain/business objects themselves. This is shown in the next two code listings for PersonPlus.java and AddressPlus.java which are versions of the previously covered Person.java and Address.java with support added for copying data to and from JAXB-generated objects. For convenience, I added the new methods to the bottom of the classes after the toString implementations.

PersonPlus.java

package dustin.examples;

import com.blogspot.marxsoftware.ObjectFactory;
import com.blogspot.marxsoftware.PersonType;
import java.util.Objects;

/**
* Person class enhanced to support copying to/from JAXB-generated PersonType.
*
* @author Dustin
*/
public class PersonPlus
{
private String lastName;
private String firstName;
private AddressPlus mailingAddress;
private AddressPlus residentialAddress;

public PersonPlus(
final String newLastName,
final String newFirstName,
final AddressPlus newResidentialAddress,
final AddressPlus newMailingAddress)
{
this.lastName = newLastName;
this.firstName = newFirstName;
this.residentialAddress = newResidentialAddress;
this.mailingAddress = newMailingAddress;
}

public String getLastName()
{
return this.lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getFirstName()
{
return this.firstName;
}

public void setFirstName(String firstName)
{
this.firstName = firstName;
}

public AddressPlus getMailingAddress()
{
return this.mailingAddress;
}

public void setMailingAddress(AddressPlus mailingAddress)
{
this.mailingAddress = mailingAddress;
}

public AddressPlus getResidentialAddress()
{
return this.residentialAddress;
}

public void setResidentialAddress(AddressPlus residentialAddress)
{
this.residentialAddress = residentialAddress;
}

@Override
public int hashCode()
{
int hash = 3;
hash = 19 * hash + Objects.hashCode(this.lastName);
hash = 19 * hash + Objects.hashCode(this.firstName);
hash = 19 * hash + Objects.hashCode(this.mailingAddress);
hash = 19 * hash + Objects.hashCode(this.residentialAddress);
return hash;
}

@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final PersonPlus other = (PersonPlus) obj;
if (!Objects.equals(this.lastName, other.lastName))
{
return false;
}
if (!Objects.equals(this.firstName, other.firstName))
{
return false;
}
if (!Objects.equals(this.mailingAddress, other.mailingAddress))
{
return false;
}
if (!Objects.equals(this.residentialAddress, other.residentialAddress))
{
return false;
}
return true;
}

@Override
public String toString() {
return "PersonPlus{" + "lastName=" + lastName + ", firstName=" + firstName
+ ", mailingAddress=" + mailingAddress + ", residentialAddress="
+ residentialAddress + '}';
}

/**
* Provide a JAXB-generated instance of {@link com.blogspot.marxsoftware.PersonType}
* that corresponds to me.
*
* @return Instance of {@link com.blogspot.marxsoftware.PersonType} that
* corresponds to me.
*/
public PersonType toPersonType()
{
final ObjectFactory objectFactory = new ObjectFactory();
final PersonType personType = objectFactory.createPersonType();
personType.setFirstName(this.firstName);
personType.setLastName(this.lastName);
personType.setResidentialAddress(this.residentialAddress.toAddressType());
personType.setMailingAddress(this.mailingAddress.toAddressType());
return personType;
}

/**
* Provide instance of {@link dustin.examples.PersonPlus} corresponding
* to the provided instance of JAXB-generated object
* {@link com.blogspot.marxsoftware.PersonType}.
*
* @param personType Instance of JAXB-generated object
* {@link com.blogspot.marxsoftware.PersonType}.
* @return Instance of me corresponding to provided JAXB-generated object
* {@link com.blogspot.marxsoftware.PersonType}.
*/
public static PersonPlus fromPersonType(final PersonType personType)
{
final AddressPlus residentialAddress =
AddressPlus.fromAddressType(personType.getResidentialAddress());
final AddressPlus mailingAddress =
AddressPlus.fromAddressType(personType.getMailingAddress());
return new PersonPlus(personType.getLastName(), personType.getFirstName(),
residentialAddress, mailingAddress);
}
}
AddressPlus.java

package dustin.examples;

import com.blogspot.marxsoftware.AddressType;
import com.blogspot.marxsoftware.ObjectFactory;
import java.util.Objects;

/**
* Address class with support for copying to/from JAXB-generated class
* {@link com.blogspot.marxsoftware.AddressType}.
*
* @author Dustin
*/
public class AddressPlus
{
private String streetAddress1;
private String streetAddress2;
private String municipality;
private String state;
private String zipCode;

public AddressPlus(
final String newStreetAddress1,
final String newStreetAddress2,
final String newMunicipality,
final String newState,
final String newZipCode)
{
this.streetAddress1 = newStreetAddress1;
this.streetAddress2 = newStreetAddress2;
this.municipality = newMunicipality;
this.state = newState;
this.zipCode = newZipCode;
}

public String getStreetAddress1()
{
return this.streetAddress1;
}

public void setStreetAddress1(String streetAddress1)
{
this.streetAddress1 = streetAddress1;
}

public String getStreetAddress2()
{
return this.streetAddress2;
}

public void setStreetAddress2(String streetAddress2)
{
this.streetAddress2 = streetAddress2;
}

public String getMunicipality()
{
return this.municipality;
}

public void setMunicipality(String municipality)
{
this.municipality = municipality;
}

public String getState() {
return this.state;
}

public void setState(String state)
{
this.state = state;
}

public String getZipCode()
{
return this.zipCode;
}

public void setZipCode(String zipCode)
{
this.zipCode = zipCode;
}

@Override
public int hashCode()
{
return Objects.hash(
this.streetAddress1, this.streetAddress2, this.municipality,
this.state, this.zipCode);
}

@Override
public boolean equals(Object obj)
{
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final AddressPlus other = (AddressPlus) obj;
if (!Objects.equals(this.streetAddress1, other.streetAddress1))
{
return false;
}
if (!Objects.equals(this.streetAddress2, other.streetAddress2))
{
return false;
}
if (!Objects.equals(this.municipality, other.municipality))
{
return false;
}
if (!Objects.equals(this.state, other.state))
{
return false;
}
if (!Objects.equals(this.zipCode, other.zipCode))
{
return false;
}
return true;
}

@Override
public String toString()
{
return "Address{" + "streetAddress1=" + streetAddress1 + ", streetAddress2="
+ streetAddress2 + ", municipality=" + municipality + ", state=" + state
+ ", zipCode=" + zipCode + '}';
}

/**
* Provide a JAXB-generated instance of {@link com.blogspot.marxsoftware.AddressType}
* that corresponds to an instance of me.
*
* @return Instance of JAXB-generated {@link com.blogspot.marxsoftware.AddressType}
* that corresponds to me.
*/
public AddressType toAddressType()
{
final ObjectFactory objectFactory = new ObjectFactory();
final AddressType addressType = objectFactory.createAddressType();
addressType.setStreetAddress1(this.streetAddress1);
addressType.setStreetAddress2(this.streetAddress2);
addressType.setCity(this.municipality);
addressType.setState(this.state);
addressType.setZipcode(this.zipCode);
return addressType;
}

/**
* Provide instance of {@link dustin.examples.AddressPlus} corresponding
* to the provided instance of JAXB-generated object
* {@link com.blogspot.marxsoftware.AddressType}.
*
* @param addressType Instance of JAXB-generated object
* {@link com.blogspot.marxsoftware.AddressType}.
* @return Instance of me corresponding to provided JAXB-generated object
* {@link com.blogspot.marxsoftware.AddressType}.
*/
public static AddressPlus fromAddressType(final AddressType addressType)
{
return new AddressPlus(
addressType.getStreetAddress1(),
addressType.getStreetAddress2(),
addressType.getCity(),
addressType.getState(),
addressType.getZipcode());
}
}

The two approaches demonstrated above for mapping JAXB-generated objects to business/domain objects will definitely work and for my simple example might be considered the best approaches to use (especially given that NetBeans made the generation of the business/domain objects almost trivial). However, for more significant object hierarchies that require mapping, the Dozer configuration-based mapping might be considered preferable.

Dozer is downloaded from the download page (dozer-5.3.2.jar in this case). The Getting Started page shows that mapping is really easy (minimal configuration) when the attributes of the classes being mapped have the same names. This is not the case in my example in which I intentionally made one attribute "city" and the other "municipality" to make the mapping more interesting. Because these names are different, I need to customize the Dozer mapping and this is done with XML mapping configuration. The necessary mapping file is named with a "default mapping name" of dozerBeanMapping.xml and is shown next. I only needed to map the two fields with different names (city and municipality) because all other fields of the two classes being mapped have the same names and are automatically mapped together without explicit configuration.

dozerBeanMapping.xml

<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns="http://dozer.sourceforge.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://dozer.sourceforge.net
http://dozer.sourceforge.net/schema/beanmapping.xsd">

<configuration>
<stop-on-errors>true</stop-on-errors>
<date-format>MM/dd/yyyy HH:mm:ss</date-format>
<wildcard>true</wildcard>
</configuration>

<mapping>
<class-a>dustin.examples.Address</class-a>
<class-b>com.blogspot.marxsoftware.AddressType</class-b>
<field>
<a>municipality</a>
<b>city</b>
</field>
</mapping>

</mappings>

Note that XML is not the only approach that can be used to customize Dozer mapping; annotations and programmatic API are also supported.

The Dozer 3rd Party Object Factories page briefly covers using Dozer with JAXB and using the JAXBBeanFactory. It is also recommended that injection be used with Dozer and an example of Spring integration is provided. For my simple example of applying Dozer, I'm not using those approaches, but use the very straight forward instantiation approach. This is shown in the next code listing.

DozerPersonConverter.java

package dustin.examples.dozerdemo;

import com.blogspot.marxsoftware.PersonType;
import dustin.examples.Person;
import java.util.ArrayList;
import java.util.List;
import org.dozer.DozerBeanMapper;

/**
* Dozer-based converter.
*
* @author Dustin
*/
public class DozerPersonConverter
{
static final DozerBeanMapper mapper = new DozerBeanMapper();

static
{
final List<String> mappingFilesNames = new ArrayList<>();
mappingFilesNames.add("dozerBeanMapping.xml");
mapper.setMappingFiles(mappingFilesNames);
}

/**
* Provide an instance of {@link com.blogspot.marxsoftware.PersonType}
* that corresponds with provided {@link dustin.examples.Person} as
* mapped by Dozer Mapper.
*
* @param person Instance of {@link dustin.examples.Person} from which
* {@link com.blogspot.marxsoftware.PersonType} will be extracted.
* @return Instance of {@link com.blogspot.marxsoftware.PersonType} that
* is based on provided {@link dustin.examples.Person} instance.
*/
public PersonType copyPersonTypeFromPerson(final Person person)
{
final PersonType personType =
mapper.map(person, PersonType.class);
return personType;
}

/**
* Provide an instance of {@link dustin.examples.Person} that corresponds
* with the provided {@link com.blogspot.marxsoftware.PersonType} as
* mapped by Dozer Mapper.
*
* @param personType Instance of {@link com.blogspot.marxsoftware.PersonType}
* from which {@link dustin.examples.Person} will be extracted.
* @return Instance of {@link dustin.examples.Person} that is based on the
* provided {@link com.blogspot.marxsoftware.PersonType}.
*/
public Person copyPersonFromPersonType(final PersonType personType)
{
final Person person =
mapper.map(personType, Person.class);
return person;
}
}

The previous example shows how little code is required to map the JAXB-generated objects to business/domain objects. Of course, there was some XML needed, but only for fields with different names. This implies that the more the names of the fields differ, the more configuration is required. However, as long as fields are mostly mapped one-to-one without any special "conversion" logic between them, Dozer replaces much of the tedious code with configuration mapping.

If fields needed to be converted (such as converting meters in one object to kilometers in another object), then this mapping support may be less appealing when custom converters must be written. Dozer mapping can also become more difficult to apply correctly with deeply nested objects, but my example did nest Address within Person as a simple example. Although complex mappings might become less appealing in Dozer, many mappings of JAXB-generated objects to business/domain objects are simple enough mappings to be well served by Dozer.

One last thing I wanted to point out in this post is that Dozer has runtime dependencies on some third-party libraries. Fortunately, these libraries are commonly used in Java projects anyway and are readily available. As the next two images indicate, the required runtime dependencies are SLF4J, Apache Commons Lang, Apache Commons Logging, and Apache BeanUtils.

Dozer Runtime Dependencies Page
NetBeans 7.4 Project Libraries for this Post's Examples

There is a small amount of effort required to set up Dozer and its dependencies and then to configure mappings, but this effort can be well rewarded with significantly reduced mapping code in many common JAXB-to-business object data copying applications.

Thứ Hai, 2 tháng 12, 2013

More Common Red Flags in Java Development

In the post Common Red Flags in Java Development I looked at some practices that are not necessarily wrong or incorrect in and of themselves, but can be indicative of potentially greater problems. These "red flags" are similar to the concept of "code smells" and some of the particular "red flags" I cite in this post have been called "code smells." As I stated in the initial post, several of these "red flags" are considered significant enough that static code analysis tools and Java IDEs will flag them.

"Logging" Messages Directly to stdout or stderr

Logging frameworks have been available for a long time in Java and today we have a wide variety of logging frameworks (some of which build on each other) including traditional Log4j 1.2, log4j 2, java.util.logging (Java Logging API), Apache Commons Logging, and SLF4J. Given this, it surprises me when I see System.out and System.err references in Java code.

There are multiple reasons that the existence of Java code directly writing to standard output or standard error is of concern. One reason for concern is that this might mean immature code that was intended to later be changed to logging but never got that finishing attention. Another disadvantage of referencing standard output and standard error is that the "logged" messages will likely not appear in the log files with the rest of the logs written by logging frameworks. A third problem is that there are numerous nice features provided by a logging framework that are not provided by simple writing to standard output and standard error. These include the ability to easily control the level of messages which are logged, the ability to control whether to take the performance hit to generate large output strings given the specified level of logging, the ability to easily associate caught exceptions with a logged error message, and the ability to easily redirect the output to different destinations and with different formats. Although all of this can be manually done when working directly with output and error streams, it requires customized work rather than being available "out of the box."

There are manifestations in Java code that write to standard output and standard error other than direct access using System.out and System.err (though they typically implicitly System.out and System.err). For example, Throwable.printStackTrace() [more commonly used in handling of Exceptions], as its Javadoc states, "Prints this throwable and its backtrace to the standard error stream."

Use of StringBuffer Rather than StringBuilder

This is admittedly a very minor thing, but it can indicate outdated Java code (StringBuffer introduced in JDK 1.0 and StringBuilder introduced in J2SE 5) or Java code where the developer did not understand the the differences between StringBuffer and StringBuilder. In most cases, the performance difference between the two is not significant to the application at hand, but because StringBuilder is preferable in most cases where I've seen StringBuffer used, one may as well enjoy the typically slight performance benefit of using StringBuilder. I'm having a difficult time recalling a single instance in which I have seen StringBuffer used in which StringBuilder could not have been used instead. A related red flag is mixing String concatenation with a StringBuilder in its constructor or overloaded append methods.

Too Many Parameters in Methods and Constructors

I'm always concerned about a method or constructor not being used correctly by its clients when the method or constructor has too many parameters, especially if several of the parameters are of the same type. If a method accepts three Strings and three booleans, for example, it is easy for the client to mix up the particular values it passes in. The compiler cannot help much in this case and the only way to detect the source of the problem (or even if a problem exists at all) is at runtime (via unit tests or other tests or, sadly, during regular execution of the software). Too many parameters can be a "red flag" for improper design as well. I am not going to look at this "red flag" any deeper in this post because I have already covered this "red flag," multiple ways to resolve it, and issues it presents in a series of eight blogs posts.

Excessive Explicit Casting

Explicit casting is probably one of the best examples of a red flag situation in which the casting itself may not affect any functionality or logic from working correctly, but is a tip-off that things are not as well as they could be. Casting can imply poor design choices (such as not using polymorphism correctly, using inheritance when inappropriate, or forcing things to go together that were never designed to go together). Explicit casting is certainly appropriate or required in many situations (such as when obtaining a Spring Framework context bean), but explicit casting can also be used as a crutch to get things working that have not been designed as carefully as they could have been. Casting can also be indicative of APIs that are too broad or interfaces used in APIs that are too broad (highlighted in the next item).

Use of Too Broad of an Interface or Class

I have often seen the Collection interface used as a method parameter or return type when Set or List or even more specific interface was more appropriate. For example, a method that returns a Collection but expects the client code to know that the returned Collection is ordered, should return a List or more specific interface or implementation of List. Likewise, if a sorted Set is expected by a method, it should advertise the method as expecting a SortedSet or similar interface or implementation class. When the interface or class returned or expected as a parameter is too broad for the given contract, somebody is forced to "know" that's the case and to cast to the appropriate level to get the functionality that they are dependent on.

Using the appropriate level or interface or class goes beyond helping avoid unnecessary explicit casting. The appropriate type level advertises and enforces the method contract better than mere documentation can. However, it goes further than that. In some cases, significant runtime exceptions can occur when the advertised interface is too broad to capture assumptions in the method's contract. For example, a generic interface might optionally support a method but the actual implementation of that interface throws an UnsupportedOperationException when called because it does not implement that optional method. Between UnsupportedOperationExceptions and ClassCastExceptions, use of overly broad interfaces or classes can lead to potentially serious runtime issues.

This is not to say that interfaces or broad classes should be avoided. Rather, it is to say that the appropriate degree of abstraction should be used in return types and parameter types so that the expected behavior for both sides of the invocation is appropriately advertised and enforced.

Use of List.addAll()

Use of one of the overloaded List.addAll() methods makes me nervous and is a bright red flag when I see it in code. That doesn't mean it's always wrong to use it, but it does seem like I've seen a lot of bloated memory issues due to misuse of this. Because Lists will add "duplicate" objects as much as the developer likes, errant code can exponentially fill these Lists up with redundant objects. Negative impacts from this range from potentially impeded performance to running out of memory. When I see use of List.addAll(), I carefully review the code and unit test it extra carefully to ensure that its memory consumption doesn't get out of control. As described in the previous "red flag," any use of Collection.addAll() must be analyzed similarly to List.addAll() until it is known for certain that the Collection is really not a List.

Non-Java Dialects

Perhaps the best example of all for me of a "red flag" is the frequent use of idioms and code conventions that are contrary or significantly different to "generally accepted Java coding standards." Nothing about using names, case, or other style issues directly impact the correctness or performance of the code. However, these discrepancies remain a "red flag" warning of potential actual problems with logic or performance because use of these significantly non-standard idioms and conventions imply that the developer may be new to Java and hence may have made mistakes common to those new to Java. A good article on the importance of writing Java code "without an accent" is Speaking the Java language without an accent. In that article, author Elliotte Rusty Harold writes about how such code is more difficult to read and maintain.

In relatively rare cases, this can move from a style issue to an impacting issue. This occurs when one writes Java code in a manner that makes most sense in a different language (such as C or C++) but does not make as much sense as alternative approaches in Java.

Conclusion

As was the case in my first post on red flags in Java code, the "red flags" discussed in this post are generally things that are not necessarily incorrect when used in appropriate and select circumstances, but often do indicate that things are not as well as they could be in the greater application.

Thứ Năm, 28 tháng 11, 2013

Uncompressing 7-Zip Files with Groovy and 7-Zip-JBinding

This post demonstrates a Groovy script for uncompressing files with the 7-Zip archive format. The two primary objectives of this post are to demonstrate uncompressing 7-Zip files with Groovy and the handy 7-Zip-JBinding and to call out and demonstrate some key characteristics of Groovy as a scripting language.

The 7-Zip page describes 7-Zip as "a file archiver with a high compression ratio." The page further adds, "7-Zip is open source software. Most of the source code is under the GNU LGPL license." More license information in available on the site along with information on the 7z format ("LZMA is default and general compression method of 7z format").

The 7-Zip page describes it as "a Java wrapper for 7-Zip C++ library" that "allows extraction of many archive formats using a very fast native library directly from Java through JNI." The 7z format is based on "LZMA and LZMA2 compression." Although there is an LZMA SDK available, it is easier to use the open source (SourceForge) 7-Zip-JBinding project when manipulating 7-Zip files with Java.

A good example of using Java with 7-Zip-JBinding to uncompress 7z files is available in the StackOverflow thread Decompress files with .7z extension in java. Dark Knight's response indicates how to use Java with 7-Zip-JBinding to uncompress a 7z file. I adapt Dark Knight's Java code into a Groovy script in this post.

To demonstrate the adapted Groovy code for uncompressing 7z files, I first need a 7z file that I can extract contents from. The next series of screen snapshots show me using Windows 7-Zip installed on my laptop to compress the six PDFs available under the Guava Downloads page into a single 7z file called Guava.7z.

Six Guava PDFs Sitting in a Folder
Contents Selected and Right-Click Menu to Compress to 7z Format
Guava.7z Compressed Archive File Created

With a 7z file in place, I now turn to the adapted Groovy script that will extract the contents of this Guava.7z file. As mentioned previously, this Groovy script is an adaptation of the Java code provided by Dark Knight on a StackOverflow thread.

unzip7z.groovy

//
// This Groovy script is adapted from Java code provided at
// http://stackoverflow.com/a/19403933


import static java.lang.System.err as error

import java.io.File
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.IOException
import java.io.RandomAccessFile
import java.util.Arrays

import net.sf.sevenzipjbinding.ExtractOperationResult
import net.sf.sevenzipjbinding.ISequentialOutStream
import net.sf.sevenzipjbinding.ISevenZipInArchive
import net.sf.sevenzipjbinding.SevenZip
import net.sf.sevenzipjbinding.SevenZipException
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream
import net.sf.sevenzipjbinding.simple.ISimpleInArchive
import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem


if (args.length < 1)
{
println "USAGE: unzip7z.groovy <fileToUnzip>.7z\n"
System.exit(-1)
}

def fileToUnzip = args[0]

try
{
RandomAccessFile randomAccessFile = new RandomAccessFile(fileToUnzip, "r")
ISevenZipInArchive inArchive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile))

ISimpleInArchive simpleInArchive = inArchive.getSimpleInterface()

println "${'Hash'.center(10)}|${'Size'.center(12)}|${'Filename'.center(10)}"
println "${'-'.multiply(10)}+${'-'.multiply(12)}+${'-'.multiply(10)}"

simpleInArchive.getArchiveItems().each
{ item ->
final int[] hash = new int[1]
if (!item.isFolder())
{
final long[] sizeArray = new long[1]
ExtractOperationResult result = item.extractSlow(
new ISequentialOutStream()
{
public int write(byte[] data) throws SevenZipException
{
//Write to file
try
{
File file = new File(item.getPath())
file.getParentFile()?.mkdirs()
FileOutputStream fos = new FileOutputStream(file)
fos.write(data)
fos.close()
}
catch (Exception e)
{
printExceptionStackTrace("Unable to write file", e)
}

hash[0] ^= Arrays.hashCode(data) // Consume data
sizeArray[0] += data.length
return data.length // Return amount of consumed data
}
})
if (result == ExtractOperationResult.OK)
{
println(String.format("%9X | %10s | %s",
hash[0], sizeArray[0], item.getPath()))
}
else
{
error.println("Error extracting item: " + result)
}
}
}
}
catch (Exception e)
{
printExceptionStackTrace("Error occurs", e)
System.exit(1)
}
finally
{
if (inArchive != null)
{
try
{
inArchive.close()
}
catch (SevenZipException e)
{
printExceptionStackTrace("Error closing archive", e)
}
}
if (randomAccessFile != null)
{
try
{
randomAccessFile.close()
}
catch (IOException e)
{
printExceptionStackTrace("Error closing file", e)
}
}
}

/**
* Prints the stack trace of the provided exception to standard error without
* Groovy meta data trace elements.
*
* @param contextMessage String message to precede stack trace and provide context.
* @param exceptionToBePrinted Exception whose Groovy-less stack trace should
* be printed to standard error.
* @return Exception derived from the provided Exception but without Groovy
* meta data calls.
*/
def Exception printExceptionStackTrace(
final String contextMessage, final Exception exceptionToBePrinted)
{
error.print "${contextMessage}: ${org.codehaus.groovy.runtime.StackTraceUtils.sanitize(exceptionToBePrinted).printStackTrace()}"
}

In my adaptation of the Java code into the Groovy script shown above, I left most of the exception handling in place. Although Groovy allows exceptions to be ignored whether they are checked or unchecked, I wanted to maintain this handling in this case to make sure resources are closed properly and that appropriate error messages are presented to users of the script.

One thing I did change was to make all of the output that is error-related be printed to standard error rather than to standard output. This required a few changes. First, I used Groovy's capability to rename something that is statically imported (see my related post Groovier Static Imports) to reference "java.lang.System.err" as "error" so that I could simply use "error" as a handle in the script rather than needing to use "System.err" to access standard error for output.

Because Throwable.printStackTrace() already writes to standard error rather than standard output, I just used it directly. However, I placed calls to it in a new method that would first run StackTraceUtils.sanitize(Throwable) to remove Groovy-specific calls associated with Groovy's runtime dynamic capabilities from the stack trace.

There were some other minor changes to the script as part of making it Groovier. I used Groovy's iteration on the items in the archive file rather than the Java for loop, removed semicolons at the ends of statements, used Groovy's String GDK extension for more controlled output reporting [to automatically center titles and to multiply a given character by the appropriate number of times it needs to exist], and took advantage of Groovy's implicit inclusion of args to add a check to ensure file for extraction was provided to the script.

With the file to be extracted in place and the Groovy script to do the extracting ready, it is time to extract the contents of the Guava.7z file I demonstrated generating earlier in this post. The following command will run the script and places the appropriate 7-Zip-JBinding JAR files on the classpath.


groovy -classpath "C:/sevenzipjbinding/lib/sevenzipjbinding.jar;C:/sevenzipjbinding/lib/sevenzipjbinding-Windows-x86.jar" unzip7z.groovy C:\Users\Dustin\Downloads\Guava\Guava.7z

Before showing the output of running the above script against the indicated Guava.7z file, it is important to note the error message that will occur if the native operating system specific 7-Zip-JBinding JAR (sevenzipjbinding-Windows-x86.jar in my laptop's case) is not included on the classpath of the script.

As the last screen snapshot indicates, neglecting to include the native JAR on the classpath leads to the error message: "Error occurs: java.lang.RuntimeException: SevenZipJBinding couldn't be initialized automaticly using initialization from platform depended JAR and the default temporary directory. Please, make sure the correct 'sevenzipjbinding-.jar' file is in the class path or consider initializing SevenZipJBinding manualy using one of the offered initialization methods: 'net.sf.sevenzipjbinding.SevenZip.init*()'"

Although I simply added C:/sevenzipjbinding/lib/sevenzipjbinding-Windows-x86.jar to my script's classpath to make it work on this laptop, a more robust script might detect the operating system and apply the appropriate JAR to the classpath for that operating system. The 7-Zip-JBinding Download page features multiple platform-specific downloads (including platform-specific JARs) such as sevenzipjbinding-4.65-1.06-rc-extr-only-Windows-amd64.zip, sevenzipjbinding-4.65-1.06-rc-extr-only-Mac-x86_64.zip, sevenzipjbinding-4.65-1.06-rc-extr-only-Mac-i386.zip, and sevenzipjbinding-4.65-1.06-rc-extr-only-Linux-i386.zip.

Once the native 7-Zip-JBinding JAR is included on the classpath along with the core sevenzipjbinding.jar JAR, the script runs beautifully as shown in the next screen snapshot.

The script extracts the contents of the 7z file into the same working directory as the Groovy script. A further enhancement would be to modify the script to accept a directory to which to write the extracted files or might write them to the same directory as the 7z archive file by default instead. Use of Groovy's built-in CLIBuilder support could also improve the script.

Groovy is my preferred language of choice when scripting something that makes use of the JVM and/or of Java libraries and frameworks. Writing the script that is the subject of this post has been another reminder of that.

Happy Thanksgiving!

Thứ Tư, 27 tháng 11, 2013

Book Review: Developing RESTful Services with JAX-RS 2.0, WebSockets, and JSON

I was particularly interested in accepting Packt Publishing's offer to provide a book review of Masoud Kalali's and Bhakti Mehta's Developing RESTful Services with JAX-RS 2.0, WebSockets, and JSON because its title mentions three things I have had good experience with (REST, JAX-RS 2.0, and JSON) as well as a concept that I only have basic familiarity with but wanted to learn more about (WebSockets). For this review, I was provided with an electronic copy of this book with about 100 pages of "regular" text and code examples.

Preface

The Preface of Developing RESTful Services with JAX-RS 2.0, WebSockets, and JSON is a good place to start if you are thinking of purchasing this book and want to get an overview of what it entails. The Preface breaks down what is in each of the five chapters with three or four sentence descriptions of each chapter.

It is also in the Preface that the reader learns that the book assumes use of Maven (final chapter only) and GlassFish Server Open Source Edition 4 (most chapters) for building and running the examples. The recent news that Oracle will not provide commercial support for GlassFish 4 has certainly added tarnish to the idea of using GlassFish 4, but it is still a valid application server to use for Java EE illustrative purposes as it remains freely available and is going to continue to be the reference implementation of the Java EE 8 specification.

Developing RESTful Services with JAX-RS 2.0, WebSockets, and JSON's Preface also states "who this book is for": "This book is ... for application developers who are familiar with Java EE and are keen to understand the new HTML5-related functionality introduced in Java EE 7 to improve productivity. To take full advantage of this book, you need to be familiar with Java EE and have some basic understanding of using GlassFish application server." I agree that readers of this book will be much better off if they have a basic understanding of Java SE and Java EE principles. Examples of this are terms that are assumed to be implicitly understood such as POJO (Plain Old Java Object) and StAX. Perhaps the most important assumed knowledge is awareness of what JSON is and how it differs from and compares to XML.

Chapter 1: Building RESTful Web Services Using JAX-RS

The initial chapter of Developing RESTful Services with JAX-RS 2.0, WebSockets, and JSON begins with a brief introduction to the basic characteristics and principles of the REST architectural style before quickly moving onto "the basic concept of building RESTful Web Services using the JAX-RS 2.0 API." The chapter states that the "Java API for Representational State Transfer (JAX-RS) specification defines a set of Java APIs for building web services conforming to the REST style." Note that JAX-RS 2.0 is standardized via JSR 339 and is more commonly as "The Java API for RESTful Web Services.

Chapter 1 provides step-by-step instructions for converting Java POJOs into RESTful resources via application of JAX-RS annotations such as @Path (defining resource), @GET (defining methods), and @Produces (defining MIME type). This section continues these step-by-step instructions by illustrating how to write an Application subclass and define subresources. Along the way, this chapter also demonstrates using curl to communicate with an HTTP-exposed service from the command line.

After covering converting a POJO to a resource and listing additional JAX-RS annotations in a handy table, the first chapter moves onto discussion of the client API for JAX-RS (this standardized client API for JAX-RS is new to 2.0). Entities, which are passed as part of requests and responses, are also covered along with custom entity providers (implementations of MessageBodyReader and MessageBodyWriter). Use of JAXB with JAX-RS is also introduced.

One part of this chapter that I found particularly interesting and useful is the inclusion of a highlighted section on "Tips for debugging errors with MessageBodyReader and MessageBodyWriter." I would like to see more books have sections like this.

Chapter 1's section on "using the Bean Validation API with JAX-RS" introduces the @ValidationOnExecution annotation as part of Java EE's Bean Validation support. The chapter's Java validation coverage also talks about extracting status responses from Response.readEntity(GenericType<T>) to handle errors.

Chapter 2: WebSockets and Server-sent Events

As the chapter's title suggests, Chapter 2 is an introduction to WebSockets and Server-Sent Events (SSEs), with Chapter 3 going into more details on these subjects. This second chapter begins with an overall view of polling between a client and server and then illustrates an example of this using an Ajax (XMLHttpRequest) JavaScript client example.

After outlining the drawbacks of polling mechanisms between clients and servers, the chapter moves onto coverage of long polling. The XMLHttpRequest of Ajax fame is then used again, but this time with significantly more explanation. The chapter includes a discussion on the disadvantages of long polling.

Chapter 2 introduces concepts that attempt to address the drawbacks and limitations of polling. Server-sent Events (SSE) (or EventSource) are described as "an HTML5 browser API that makes event pushing between server and client available to web application developers." The authors add, "The major SSE API that is considered the foundation of SSE in the client side for JavaScript developers is the EventSource interface." Code listings are provided to illustrate SSE implemented via Java servlet on the server side and JavaScript on the client side along with a JSP example that embeds JavaScript.

WebSockets are the theme of the remainder of Chapter 2 and are described as a "component of HTML5" that "adds a brand new method for interaction between clients and servers to address the scalability and flexibility required for modern web-scale applications by introducing a full duplex event-based communication channel between clients and servers." Chapter 2 mentions that modern browsers support WebSockets and discusses operations available on a JavaScript WebSockets object.

The authors mention that Java EE 7 provides "full support for HTML5, SSE and WebSockets" and references JSR 356 ("Java API for WebSocket").

This information-packed second chapter begins to wind down with a table comparing characteristics (browser performance, communication channel, and complexity) of the three covered communication approaches (long polling, Server-Sent Events, and WebSockets). I liked the fact that the chapter then concludes with example use cases/scenarios where each of the three approaches to asynchronous web communication is best suited.

I found it a bit odd that the second chapter has the side note referencing Jersey as the JAX-RS reference implementation rather than the first chapter (which was devoted to JAX-RS) including that side note. A more appropriate side note for this chapter references the article Memory Leak Patterns in JavaScript.

Chapter 3: Understanding WebSockets and Server-sent Events in Detail

Chapter 3 dives more deeply into the concepts introduced in Chapter 2. These more in-depth topics related to WebSockets include encoders and decoders in the Java API for WebSockets (@ServerEndpoint), Java WebSocket Client API (@ClientEndpoint), sending blob/binary data rather than text (JSON/XML), WebSockets security (including example in GlassFish), and three best practices for WebSockets applications. The more in-depth topics on Server-sent Events covered in the third chapter include an example of developing a Server-sent Event client using Jersey API and three "best practices for applications based on Server-sent Events."

The third chapter introduces JSON and JSON-P.

Chapter 4: JSON and Asynchronous Processing

The fourth chapter of Developing RESTful Services with JAX-RS 2.0, WebSockets, and JSON covers JSR 353 ("Java API for JSON Processing") and "related APIs." The chapter explains that Java EE 7 adds JSON support that replaces less standard open source Java JSON processing products such as google-gson and Jackson.

Chapter 4 provides a nice overview of the JSON API and includes a table that lists the classes provided along with a description of the classes and how those classes are used. The authors state that "JSONObject is the entry point to the entire JSON API arsenal," but it is the Json class that provides factory methods for creating instances of other classes in the JSON API. The chapter covers generating JSON documents (JsonGeneratorFactory and JsonGenerator), parsing JSON documents (JsonParser), using JSON object model to generate JSON (JsonBuilderFactory and JsonObject), and using JSON object model to parse JSON (JsonReader and JsonObject). A quick paragraph contrasts when to use the streaming approaches versus the object model approaches for generating and parsing JSON; the trade-off is similar to that between StAX and DOM (memory considerations versus ease of use).

The next section of Chapter 4 covers Servlet 3.1 enhancements with specific focus on NIO additions to servlets (ReadListener and WriteListener) and WebSockets support in servlets. Changes to servlets to support this new functionality are covered and include ServletOutputStream, ServletInputStream, @WebServlet asyncSupported attribute, asynchronous request and response processing, and JAX-RS 2.0 filters and interceptors.

The authors introduce asynchronous support with EJB 3.1 and 3.2 and include an interesting observation: "In Java EE 6, the @Asynchronous [annotation] was only available in full profile while in Java EE 7 the annotation is added to the web profile as well."

One of the interesting side notes of this chapter is mention that key JSON API classes can be used with the Automatic Resource Management (try-with-resources) mechanism introduced with Java SE 7.

Chapter 5: RESTful Web Services by Example

While the first four chapters of Developing RESTful Services with JAX-RS 2.0, WebSockets, and JSON are packed with new information and details related to writing RESTful web services with Java EE, JAX-RS 2.0, WebSockets, and JSON, the fifth and final chapter provides two examples of applying these concepts and technologies to representative use cases. The samples in this chapter are built with Maven and deployed to GlassFish.

As the authors advertised at the beginning of the chapter, these two samples do illustrate integrated application of topics covered in the prior chapters of the book. The first sample employs Server-sent Events, Asynchronous Servlet, JSON-P API, JAX-RS 2.0, EJB Timers (@Schedules) and the Twitter Search API (including Twitter's OAuth support and Twitter4j).

The second Chapter 5 example demonstrates integration and application of WebSockets, JAX-RS/HTTP "verbs" (GET, DELETE, POST), using JSON-P for writing JSON documents, and leveraging asynchronous benefits. I like the approach this book has taken of using four information-heavy chapters to introduce concepts and then devoting the entire final chapter to examples of how to integrate these concepts into realistic sample applications.

Miscellaneous Observations

The following are some miscellaneous observations I have made regarding Developing RESTful Services with JAX-RS 2.0, WebSockets, and JSON.

  • Covers a lot of material in a relatively small number of pages.
  • Has some interesting and useful emphasized side notes.
  • Lacks a lot of color in the graphics and screen snapshots, meaning the printed book probably does not lose much in way of presentation when compared to the electronic versions.
  • There are some type-setting issues, especially in code samples, where some spaces are missing that would normally separate types, variable names, and so forth.
  • Although Maven and GlassFish are used in the book, many of the examples could be tweaked to build with a Ant, Gradle, or other build system and to be deployed to an application server other than GlassFish.
  • Some experience with Java EE, HTML, and REST/HTTP concepts is assumed. More experience in these areas will obviously make the book more approachable, but only basic familiarity is needed to understand the concepts in this book.
Conclusion

This book is what its title and its preface describe: a book that details how to develop RESTful services with JAX-RS 2.0, WebSockets, JSON, and more. As the authors state in the Preface, this best is best suited for developers with at least minimal Java EE knowledge as there is some assumed knowledge in a book that covers this much in a little over 100 pages.

Thứ Hai, 25 tháng 11, 2013

Book Review: Developing Windows Store Apps with HTML5 and JavaScript

I recently accepted Packt Publishing's invitation to review Rami Sarieddine's book Developing Windows Store Apps with HTML5 and JavaScript. The Preface of the book describes the book as "a practical, hands-on guide that covers the basic and important features of a Windows Store app along with code examples that will show you how to develop these features." The Preface adds that the book is for "all developers who want to start creating apps for Windows 8" and for "everyone who wants to learn the basics of developing a Windows Store app."

Chapter 1: HTML5 Structure

Chapter 1 of Developing Windows Store Apps with HTML5 and JavaScript introduces "HTML5 structural elements" (semantic elements, media elements, form elements, custom data attributes) supported in the Windows 8 environment.

The section on semantic elements covers elements such as <header>, <nav>, <article>, and <address>. The section on media elements provides detailed coverage of the <video> and <audio> elements.

The section on form elements discusses the "new values for the type attribute are introduced to the <input> element." A table is used to display the various types (examples include tel, email, and search) with descriptions. There is discussion on these input types along with how to add validation to the input types.

Most of this initial chapter of Developing Windows Store Apps with HTML5 and JavaScript covers general HTML5 functionality, but there are a few references to items specific to Windows 8. For example, the last new material before the first chapter's Summary is on "using the Windows Library for JavaScript (WinJS) to achieve more advanced binding of data to HTML elements."

Chapter 2: Styling with CSS3

Like the first chapter, Chapter 2 focuses mostly on a general web concept, in this case Cascading Style Sheets (CSS). Sarieddine states that CSS is responsible for "defining the layout, the positioning, and the styling" of HTML elements such as those covered in the first chapter.

In introducing CSS, the second chapter of Developing Windows Store Apps with HTML5 and JavaScript provides an overview of four standard selectors (asterisk, ID, class, and element), attribute selectors (including prefix, suffix, substring [AKA contains], hyphen, and whitespace), combinator selectors (including descendant, child/direct, adjacent sibling, and general sibling), pseudo-class selectors, and pseudo-element selectors.

Chapter 2 does cover some Microsoft/Windows-specific items. Specifically, the chapter introduces the Grid layout and the Flexbox layout. The author explains that these have -ms prefixes because they are currently specific to Microsoft (Windows 8/Internet Explorer 10), but that they are moving through the W3C standardization process.

The second chapter of Developing Windows Store Apps with HTML5 and JavaScript covers animation with CSS and introduces CSS transforms before concluding with brief discussion of CSS media queries.

Chapter 3: JavaScript for Windows Apps

Developing Windows Store Apps with HTML5 and JavaScript's third chapter covers "features provided by the Windows Library for JavaScript (the WinJS library) that has been introduced by Microsoft to provide access to Windows Runtime for the Windows Store apps using JavaScript." The delivered implication of this is that this is the first chapter of the book that is heavily focused on developing specifically Windows Store Apps.

Sarieddine covers use of Promise objects to implement asynchronous programming in JavaScript's single-threaded environment rather than using callback functions directly. The author also covers use of the WinJS.Utilities namespace wrappers of document.querySelector and querySelectorAll. Coverage of the WinJS.xhr function begins with the description of it being a wrapper to "calls to XMLHttpRequest in a Promise object."

Chapter 3 concludes with a discussion of "standard built-in HTML controls" as well as WinJS-provided controls "new and feature-rich controls designed for Windows Store apps using JavaScript." This discussion includes how WinJS-provided controls are handled differently in terms of code than standard HTML controls.

This third chapter is heavily WinJS-oriented. It also includes the first non-trivial discussion and illustrations related to use of Visual Studio, a subject receiving even more focus in the fourth chapter.

Chapter 4: Developing Apps with JavaScript

Chapter 4 of Developing Windows Store Apps with HTML5 and JavaScript is intended to help the reader "get started with developing a Windows 8 app using JavaScript." It was early in this chapter that I learned that Windows Store apps run only on Windows 8. The chapter discusses two approaches for acquiring Windows 8 and downloading necessary development tools such as Visual Studio Express 2012 for Windows 8 from Windows Dev Center. The chapter discusses how to obtain or renew a free developer license via Visual Studio.

The fourth chapter also discusses languages other than HTML5/CSS3 that can be used to develop Windows Store apps. It then moves onto covering development using Visual Studio templates. Several pages are devoted to discussion on using these standard templates and there are several illustrations of applying Visual Studio in this development.

Chapter 5: Binding Data to the App

The fifth chapter of Developing Windows Store Apps with HTML5 and JavaScript discusses "how to implement data binding from different data sources to the elements in the app." As part of this discussion of data binding, the chapter covers the WinJS.Binding namespace ("Windows library for JavaScript binding") for binding styles and data to HTML elements. Examples in this section illustrate updating of HTML elements' values and styles.

Interestingly, it is in this fifth chapter that the author points out that "Windows 8 JavaScript has native support for JSON." The chapter's examples also discuss and illustrate use of Windows.Storage.

Chapter 5's coverage of formatting and displaying data introduces "the most famous controls" of ListView and FlipView and then focuses on ListView. This portion of the chapter then moves on to illustrate use of WinJS templates (WinJS.Binding.Template). The final topic of Chapter 5 is sorting and filtering data and more example code is used here for illustration.

Chapter 6: Making the App Responsive

Chapter 6 focuses on how to make a Windows 8 application "responsive so that it handles screen sizes and view state changes and responds to zooming in and out." The chapter begins by introducing view states: full screen landscape, full screen portrait, snapped view, and filled view. The chapter discusses snapping (required for apps to support) and rotation (recommended for apps to support). It then moves onto covering use of "CSS media queries" and "JavaScript layout change events."

Chapter 6 also introduces semantic zoom, described on the Guidelines for Semantic Zoom page as "a touch-optimized technique used by Windows Store apps in Windows 8 for presenting and navigating large sets of related data or content within a single view." Sarieddine describes semantic zoom as a technique "used by Windows Store apps for presenting—in a single view—two levels of detail for large sets of related content while providing quicker navigation." There are several pages of code illustrations and explanatory text on incorporating semantic zoom in the Windows 8 application.

Chapter 7: Making the App Live with Tiles and Notifications

The seventh chapter of Developing Windows Store Apps with HTML5 and JavaScript introduces the concept of Windows 8 tiles. The chapter discusses the app tile ("a core part of your app") and live tiles ("shows the best of what's happening inside the app"). Windows 8 Badges and Notifications are also covered in this chapter.

Chapter 8: Signing Users In

Chapter 8 is focused on authentication in a Windows 8 app. The chapter discusses use of the Windows 8 SDK and "a set of APIs" that "allow Windows Store apps to enable single sign on with Microsoft accounts and to integrate with info in Microsoft SkyDrive, Outlook.com, and Windows Live Messenger."

The eighth chapter's coverage includes discussion of open standards supported by Live Connect: OAuth 2.0, REST, and JSON. The chapter also covers reserving an app name on the Windows store, working with Visual Studio 2012 for Windows 8, and working with Live SDK downloads.

Chapter 9: Adding Menus and Commands

Chapter 9 of Developing Windows Store Apps with HTML5 and JavaScript focuses on adding menus and commands to the app bar. This coverage includes discussion on where to place the app bar and how the UX guidelines recommend placing the app bar on the bottom because the navigation bar goes on top of a Windows 8 app.

Chapter 10: Packaging and Publishing

Developing Windows Store Apps with HTML5 and JavaScript's tenth chapter introduces the Windows Store and likens it to "a huge shopping mall" in which the reader's new app would be like "a small shop in that mall." The author states that the Windows Store Dashboard is "the place where you submit the app, pave its way to the market, and monitor how it is doing there."

The first step in the process of submitting a Windows app to the Windows Store for certification was covered in the chapter on authentication (Chapter 8) and this chapter picks up where that left off. Steps covered in this chapter include providing the application name, setting the "selling details," adding services, setting age and rating certifications, specifying cryptography and encryption used by the app, uploading app packages generated with Visual Studio, adding app description and other metadata about the app, and notes to testers evaluating app for Windows Store.

The chapter moves from coverage of the Windows App submission process using Windows Store Dashboard to using Visual Studio's embedded Windows Store support. Of particular interest in this section is coverage of how to use Visual Studio to package a Windows 8 app so that the "package is consistent with all the app-specific and developer-specific details that the Store requires."

The majority of this chapter's examples depend on having a Windows Store developer account. The chapter also includes a reference to a page on avoiding common certification failures.

Chapter 11: Developing Apps with XAML

All of the earlier chapters of Developing Windows Store Apps with HTML5 and JavaScript focused on developing Windows Store apps with traditional web development technologies HTML, CSS, and JavaScript, but the final chapter looks at using different platforms for creating Windows Store Apps. Although most of this chapter looks at developing Windows Store apps using the alternate development platform of XAML/C#, there is brief discussion of more general considerations when using alternate platforms for developing Windows Store apps. The chapter specifically mentions multiple approaches using C++ and C# to develop Windows Store apps.

Using Extensible Application Markup Language (XAML) for developing Windows 8 applications is described similar to the approach used for JavaScript as discussed earlier in this book. One of the examples demonstrates using Visual Studio standard Windows Store App templates such as Blank App (XAML), Grid App (XAML), and Split App (XAML). The chapter dives into basics of developing an XAML-based Windows Store app and introduces XAML based on HTML and XML concepts and differences.

The final chapter has a "Summary" section, but the final paragraph of that chapter is actually a summary of the entire book. A potential purchaser of this book could read this final paragraph on page 158 to get a quick overview of what the book covers.

Targeted Audience

Developing Windows Store Apps with HTML5 and JavaScript is well-titled in terms of describing what the book is about. The book clearly fulfills its objective of demonstrating how to use HTML5 and JavaScript to develop Windows Store Apps. Although the book does briefly discuss other technologies and platforms for building Windows Store Apps, these discussions are very brief and and mostly references rather than detailed descriptions.

The reader most likely to benefit from this book is a developer interested in applying HTML, JavaScript, and CSS to develop Windows Store apps. The book does provide introductory material on these technologies for those not familiar with them, but at least some minor HTML/CSS/JavaScript experience would be a benefit for the reader.

This book would obviously not be a good fit for someone wishing to learn how to develop apps for any environment other than the Windows Store and it would only be of marginal benefit to readers wanting to develop Windows Store apps with technologies other than HTML, JavaScript, and CSS.

Conclusion

Developing Windows Store Apps with HTML5 and JavaScript delivers on what its title advertises. It provides as comprehensive of an introduction as roughly 160 pages allows to developing and deploying Windows Store apps using JavaScript and HTML. Packt Publishing provided me a PDF for this review and one of the advantages of the electronic form is the numerous screen snapshots of Windows 8 apps and Visual Studio are in full color. I especially liked that little time was wasted in the book and it efficiently covered quite a bit of ground in a relatively short number of pages.

Additional Information

Here are some additional references related to this book including other reviews of this book.

Thứ Hai, 18 tháng 11, 2013

Native Java Packaging with NetBeans 7.4

One of the new features of NetBeans 7.4 that made the "NetBeans 74 NewAndNoteworthy" page is "Native Packaging," which is described on that page as "JavaSE projects now support creation of native bundles taking use of the native packaging technology provided by JavaFX."

I will use a very simple example to demonstrate this native packaging functionality in NetBeans 7.4. The next code listing is for this enhanced Hello World example.

EnhancedHelloWorld.java

package dustin.examples;

import static java.lang.System.out;

/**
* Slightly enhanced "Hello World" example.
*
* @author Dustin
*/
public class EnhancedHelloWorld
{
/**
* Main function.
*
* @param args the command line arguments; name being addressed, if any.
*/
public static void main(String[] args)
{
final String addresseeName = args.length > 0 ? args[0] : "World";
out.println("Hello, " + addresseeName);
}
}

The next image shows this same code in the NetBeans 7.4 source code editor.

To use the Native Packaging feature, I can right-click on the project and select Properties as shown in the next image.

Clicking on "Properties" leads to the appearance of the "Project Properties" window. This window, as shown in the next screen snapshot, allows the developer to expand the "Build", select "Deployment", and check the box next to the label "Enable Native Packaging Actions in Project Menu." Selecting this option configures NetBeans 7.4 to support native packaging for that NetBeans project.

With NetBeans 7.4 native packaging enabled, I can now right-click on the project and have a new option called "Package as" available. When I select that "Package as" option, I see the following choices: "All Artifacts", "All Installers", "Image Only", "EXE Installer", and "MSI Installer". Note that my NetBeans 7.4 IDE is running on a Windows machine, so the EXE and MSI installers make sense. Sections 6.4.1 and 6.4.2 of the Deploying JavaFX Applications document cover the EXE and MSI installer packages respectively.

When I select EXE as the installer package, I see it processing the native packaging per the message in the bottom right corner of the IDE. This is shown in the next screen snapshot.

The first time I tried this, I ran into an error reported by NetBeans with the message: "JavaFX native packager requires external Inno Setup 5+ tools installed and included on PATH to create EXE installer. See http://www.jrsoftware.org/". Going to the referenced Jordan Russell Software site allows me to download Inno Setup 5.5.4 (isetup-5.5.4.exe). In my case, I downloaded the self-extracting EXE and ran it. I then added the full path to the directory into which Inno Setup 5.5.4 was installed to my PATH environmental variable and restarted NetBeans 7.4.

With Inno Setup installed on my system, the Inno Setup 5.5.4 installer compiler runs when NetBeans's EXE native packaging is selected. When NetBeans and Inno Setup complete, a relatively large EXE file exists in the project's directory as shown in the next screen snapshot.

I can run this executable, of course, by simply typing its name at the command prompt. The next screen snapshot demonstrates that running this executable leads to a popup window requesting approval to install the Java application.

When the "Install" button is clicked, the installation begins and this is demonstrated in the next screen snapshot.

The executable installer installs the Java application as another executable. In this case, this application is installed in C:\Users\Dustin\AppData\Local\EnhancedHelloWorld as shown in the next screen snapshot.

The generated directory shown in the screen snapshot above includes a "runtime" directory with the necessary JRE to run this application even on machines that don't have a JRE installed. The Java application itself is stored as a JAR in the "app" directory. Both of these subdirectories are shown in the next two screen snapshots.

The generated directory includes two .exe files. One is EnhancedHelloWorld.exe, which is the Java application executable. The other .exe file is unins000.exe. Running this latter .exe file cleanly uninstalls the application from the computer.

The next screen snapshot shows that I am able to start the application from my Window Start in addition to clicking on the generated executable file.

Although the Java code sample I started with can be built as an executable application using NetBeans 7.4 as shown in this post, it is far more interesting to use a Java application with a user interface because standard output is not written anywhere visible to the user. For example, one could build an executable application with NetBeans 7.4 based on the Java class HelloWorldSwing.

My examples in this post have been entirely Java SE (no JavaFX), but have taken advantage of NetBeans 7.4's support of native packaging via mechanisms generated for JavaFX deployments. Therefore it's not surprising that the JavaFX documentation on Self-Contained Application Packaging is useful for understanding the options available. Native packaging with NetBeans 7.4 is also demonstrated in Native Packaging in NetBeans IDE.

Addendum

Based on feedback comments to this post, I have added this clarifying section.

The primary use of native packaging would be for situations where one wants to make a Java-based application available to customers who might not have an appropriate Java Runtime Environment installed on their machines. This approach "packages" the application with the necessary runtime support classes. As grelf.net points out, it is easier if all the customers already have appropriate versions of the JRE installed on their machines. In that case, the deployment might be as simple as delivering an executable JAR.

The feedback from iyoskusmana reminded me of two other points I wanted to make clearer. The example Java code I started my post with works in the sense of giving me something to build and deploy from NetBeans 7.4. The downside of that particular code, however, is that its standard output does not get written to anywhere the user of the application can see. Although it does run, there is not much evidence of that. This is why it is better to use a Swing-based GUI application such as the suggested HelloWorldSwing.

It is also important to set the class whose "main" function should be used by the natively packaged application in the Project Properties "Run" section (MainClass field). In other words, treat the native application deployment like you would an executable JAR and specify to NetBeans which of the classes in that JAR is the one whose "main" function should be executed when the application is executed.