Using the lang Extensions


Using the lang Extensions

The lang package contains a number of routines that solve a number of smaller problems. These smaller problems are convenience issues. For example, Java does not support enumerations, which allow you to define types using alphabetic identifiers; the lang package does. We've already talked a bit about the lang package. In this chapter, we will discuss only aspects of this package that we haven't discussed.

Technical Details for the lang Package

Tables 9.3 and 9.4 contain the abbreviated details necessary to use the lang package.

Table 9.3: Repository details for the lang package.

Item

Details

CVS repository

jakarta-commons

Directory within repository

lang

Main packages used

org.apache.commons.lang: Contains all the utility classes needed for the smaller, tedious tasks (all of the useful classes are defined later in the chapter).

org.apache.commons.lang.enum: Contains the enumeration classes used to create enumerators.

org.apache.commons.builder: Contains the classes used to help implement the common object methods such as toString, and equals.

Table 9.4: Package and class details (legend: [lang] = org.apache.commons.lang).

Interface

Details

[lang].enum.Enum

A class used to implement an enumeration.

[lang].builder.HashCodeBuilder

A class used to simplify the implementation of the method hashCode .

[lang].builder.CompareToBuilder

A class used to simplify the implementation of the method compareTo .

[lang].builder.EqualsBuilder

A class used to simplify the implementation of the method equals .

[lang].builder.ToStringBuilder

A class used to simplify the implementation of the method toString .

[lang].builder.ToStringStyler

A class used to define a toString output styling.

Managing Enumerations

Enumerations do not exist in Java. The class solution has been to create a static class containing variables that represents an enumeration. The lang package exposes a class called Enum that is extended and makes it possible to build an enumeration. A sample shape enumeration class is defined in Listing 9.16.

Listing 9.16
start example
 class ShapeEnum extends Enum { public static final ShapeEnum CIRCLE = new ShapeEnum( "circle"); public static final ShapeEnum SQUARE = new ShapeEnum( "square"); public static final ShapeEnum TRIANGLE = new ShapeEnum( "triangle"); public ShapeEnum( String shape) { super( shape); } public static ShapeEnum getEnum(String shape) { return (ShapeEnum) getEnum(ShapeEnum.class, shape); } public static Map getEnumMap() { return getEnumMap(ShapeEnum.class); } public static List getEnumList() { return getEnumList(ShapeEnum.class); } public static Iterator iterator() { return iterator(ShapeEnum.class); } } 
end example
 

In Listing 9.16, the class ShapeEnum defines a shape enumeration. The enumeration is created by the variables CIRCLE , SQUARE , and TRIANGLE . Each of the variables is an instance of the class ShapeEnum . The instances are stored as a key value pair within the class ShapeEnum . The advantage of using this class is that using the defined methods, you can get an Iterator , List , or Map instance. Each of the instances can then be used to iterate through the content.

If you want, you can extend the ShapeEnum class to define a more complex shape, as defined in Listing 9.17.

Listing 9.17
start example
 class ComplexShapeEnum extends ShapeEnum { public static final ComplexShapeEnum OCTAGON = new ComplexShapeEnum( "octagon"); public ComplexShapeEnum( String shape) { super( shape); } public static ShapeEnum getEnum(String shape) { return (ShapeEnum) getEnum(ComplexShapeEnum.class, shape); } public static Map getEnumMap() { return getEnumMap(ComplexShapeEnum.class); } public static List getEnumList() { return getEnumList(ComplexShapeEnum.class); } public static Iterator iterator() { return iterator(ComplexShapeEnum.class); } } 
end example
 

In Listing 9.17, the class ComplexShapeEnum extends the class ShapeEnum and adds the additional shape OCTAGON. The individual Map , Iterator , and List methods return a list that includes the three shapes in the class ShapeEnum , plus the extra shape defined in the class ComplexShapeEnum .

The example shown in Listing 9.17 fulfills the need for an enumeration. However, Listing 9.18 shows another context of showing how to define an enumeration.

Listing 9.18
start example
 class PlainEnum extends Enum { public PlainEnum( String name) { super(name); } public static Iterator iterator() { return iterator(ComplexShapeEnum.class); } } 
end example
 

In Listing 9.18, an enumerator is created, but no enumeration values are defined. There is only one method, which returns an Iterator class instance. It is not obvious what would be returned because the class PlainEnum has no enumerator values defined. The answer lies in the method iterator , which has a single parameter. The single parameter is the class descriptor ComplexShapeEnum.class . What this parameter does is retrieve all of the enumerator values associated with the class type. The iterator method then returns the enumerator values defined in Listing 9.17, which is a list of one shape: OCTAGON . What is important about this technique is that it is possible for one enumerator to be a specific collection of enumeration values based on other enumerators. The consumer of the specific collection will not realize that the enumeration values are from another, simpler enumerator.

Utility Type Classes

Imagine having a Boolean string buffer with the value "true." The boolean value object is not a string-based value but a numeric value type. What is desired is to change a string "true" to a value true . There are longer, more complex ways to do the conversion, but we want a quick and easy way to do the conversion. Well, that is the purpose of the utility data classes in the lang package. These classes make it simpler to do the things that you often need to do but that often require a few extra steps. For reference purposes, Listing 9.19 converts the buffer to a Boolean value true .

Listing 9.19
start example
 boolean value = BooleanUtils.toBoolean( "true"); 
end example
 

The lang package contains not only a utility class to convert a Boolean, but classes that execute many utility-type tasks. Here are all of the available utility classes:

  • ArrayUtils : A class that contains utilities to manage arrays. The arrays that can be managed are basic value type arrays, such as double [] or int []. Objects are managed using Object [] arrays. Some definitions represent empty arrays. This is extremely useful for those methods that return arrays. Traditionally, some methods return a null , which is incorrect (they should return an empty array). Some methods clone an array, find an element, reverse the array, or check the lengths of the array.

  • BooleanUtils : A class used to manage Boolean values. Some routines convert a string to a Boolean value or Boolean object, or vice versa. One very useful aspect of this class is that you can convert a true / false Boolean into a yes / no or on / off Boolean value.

  • CharSetUtils : A class used to manage a String buffer. The objective of the class is to manipulate a buffer and perform specific character manipulation operations. Operations include counting, deleting, and removing specific characters or sets of characters .

  • ClassUtils : A class used to manipulate other classes without using reflection, which is the process of figuring out the structure of a class using methods while the program is executing. Some routines find out the package name for a class or the interfaces implemented by a specific class. This class is useful for finding out specific attributes about a class in the context of dynamic plug-ins.

  • NumberUtils : A class that provides extra functionality that complements the Java Number classes. For example, there are some static declarations for the values -1 , 1 , or . Included are methods to convert strings into BigInteger class instances. Another example is finding the maximum, or minimum, values in a set.

  • RandomStringUtils : A class that creates a String buffer of random characters. This class is very useful when you need to create random file names or identifiers that have a specific character length.

  • SerializationUtils : A class that helps you create serialization routines. For example, the method clone implements a deep clone. In addition, some routines help with serialization to from an array of bytes, which could be used to save to a file or buffer stream.

  • StringEscapeUtils : A class used to escape and unescape to and from Java, JavaScript, HTML, and XML.

  • StringPrintWriter : A PrintWrite implementation that maintains all of the written data as a String buffer.

  • StringUtils : A class used to manage a String buffer. The difference between this class and CharSet is that this class performs operations on the overall buffer and not character sets. Some methods capitalize or abbreviate text. For example, abbreviating text allows you to provide a predetermined length of text, without cutting out a word in the middle. Other routines center a string in a buffer, find the difference between two buffers, or pad strings with spaces. Overall, the class StringUtils is extremely useful because it helps a developer clean up a text buffer using some specific rules.

  • SystemUtils : A class to figure out what environment the JVM is operating in. For example, it tells you if the JVM is operating in 1.3 or 1.4 JDK mode, or what the classpath is. If the property cannot be determined, then an error is generated.

  • WordWrapUtils : A class used to help in word wrapping a buffer according to specific dimensions.

Implementing the Method toString

Implementing the method toString is a good programming habit. However, the good habits tend to be tedious. Within the org.apache.commons.lang.builder package are a number of classes that help the developer implement the tedious methods.

To implement the toString method, the class ToStringBuilder is used as shown in Listing 9.20 (note that part of the class has been abbreviated for clarity).

Listing 9.20
start example
 public class BuilderBean implements java.io.Serializable { protected int _iValue; protected String _strValue; protected ChildBean _beanValue = new ChildBean( 2345, "childbean"); public String toString() { return new ToStringBuilder( this) .append( "integerValue", _iValue) .append( "stringValue", _strValue) .append( "beanValue", _beanValue) .toString(); } } 
end example
 

In Listing 9.20, the class BuilderBean has two properties: _iValue and _strValue . The method toString is implemented by instantiating the class ToStringBuilder . Then, the method append is repeatedly called for each property to output. Finally, to construct the string, the method toString is called. Output should be something similar to Listing 9.21.

Listing 9.21
start example
 .com.devspace.jseng.algorithms.BuilderBean@af8358[ integerValue=1234,stringValue=hello, beanValue=com.devspace.jseng.algorithms.ChildBean@1f4689e] 
end example
 

The generated output in Listing 9.21 generates the class instance identifier and the individual property values. The properties integerValue and stringValue are displayed in a clear and easy-to-read format. What is not as clear is the property value of the bean property beanValue . This is because the class ChildBean has not implemented the method toString itself. Had the class ChildBean implemented a toString method, then the output from that method would have been in Listing 9.21 instead of in the object instance reference.

Another way of generating a similar output is to use the method reflectionString, as shown in Listing 9.22.

Listing 9.22
start example
 public String toString() { return new ToStringBuilder( this).reflectionToString( this); } 
end example
 

In Listing 9.22, the implementation of the method toString using the method reflectionToString is simpler than the similar implementation in Listing 9.20. The method reflectionToString uses reflection to figure out what properties exist and displays them like in Listing 9.23.

Listing 9.23
start example
 com.devspace.jseng.algorithms.BuilderBean@b61fd1[ _iValue=1234,_strValue=hello, _beanValue=com.devspace.jseng.algorithms.ChildBean@1adc30] 
end example
 

The output of Listing 9.23 is very similar to the output of Listing 9.21. The major difference is the labeling of the property identifiers, which are discovered using reflection. When you use reflection to generate the properties, it would appear that the output is identical, but there is a big difference. If any of the properties have the attribute transient, then the property value will not be output using the reflection method.

In the constructor of the class ToStringBuilder, you can specify how the output of the string is generated. The default is to output everything on one line. However, in Listing 9.24, the output is generated using the multiple-line string output style.

Listing 9.24
start example
 public String toString() { return new ToStringBuilder( this, ToStringStyle.MULTI_LINE_STYLE) .append( "integerValue", _iValue) .append( "stringValue", _strValue) .append( "beanValue", _beanValue) .toString(); } 
end example
 

In Listing 9.23, the style type is defined using the class declaration ToString-Style.MULTI_LINE_STYLE . The output generated is shown in Listing 9.25.

Listing 9.25
start example
 com.devspace.jseng.algorithms.BuilderBean@b61fd1[ integerValue=1234 stringValue=hello beanValue=com.devspace.jseng.algorithms.ChildBean@1c99159 ] 
end example
 

The style MULTI_LINE_STYLE is one of four default styles provided by the class ToStringStyle . You can generate custom styles by instantiating the class StandardToStringBuilder and then tweaking the individual properties. For example, you can tweak the headers and footers of the output. You can't, however, instantiate the class ToStringStyle outside of the lang package.

Implementing the Method compareTo

You use the interface Comparable to compare two objects for equality, less than, or greater than value. Any class that implements the interface Comparable has to implement the method compareTo . Listing 9.26 is an implementation of the compareTo method for the class BuilderBean defined in Listing 9.20.

Listing 9.26
start example
 public int compareTo( Object o) { BuilderBean other = (BuilderBean)o; return new CompareToBuilder() //.appendSuper( super.compareTo()) .append( _iValue, other._iValue) .append( _strValue, other._strValue) .append( _beanValue, other._beanValue) .toComparison(); } 
end example
 

In Listing 9.26, the implementation of the method compareTo is similar to the implementation of the method toString . The similarity lies in the usage of a builder-type class, and the properties are appended, with a final method to perform the actual operation. The builder-type class is the class CompareToBuilder, and the final method is the method toComparison . The individual append method calls can be called on all property types. The only catch is that, in the case of the property _beanValue , the accompanying class must also support the interface Comparable. If not then a cast exception will be generated.

In Listing 9.26, the method appendSuper is commented out because the class BuilderBean does not subclass another class. However, if the class BuilderBean did, then it would be necessary to call the method appendSuper and the method super.compareTo to do a comparison with the subclasses.

Like the ToStringBuilder class, the class CompareToBuilder has a method that uses reflection to perform the comparison, as shown in Listing 9.27.

Listing 9.27
start example
 public int compareTo( Object o) { return new CompareToBuilder().reflectionCompare( this, o); } 
end example
 

In Listing 9.27, the method reflectionCompare performs a comparison using reflection. The same rules regarding the modifier transient applies, in that the modifier will cause a property to be ignored.

Implementing the Method equals

Implementing the method equals can be a challenge because people implement it in different ways. This is why the class EqualsBuilder is all the more useful, since it implements the equals method consistently. Listing 9.28 is a sample implementation.

Listing 9.28
start example
 public boolean equals(Object o) { BuilderBean other = (BuilderBean)o; return new EqualsBuilder() //.appendSuper( super.equals( o)) .append( _iValue, other._iValue) .append( _strValue, other._strValue) .append( _beanValue, other._beanValue) .isEquals(); } 
end example
 

In Listing 9.28, the method equals is implemented almost identically to the previous methods, like compareTo or toString . The only difference is the name of the implementing classes. In Listing 9.28, the method appendSuper has been commented out. This is because the bean class subclasses the class Object . In addition, the method Object.equals returns true only if the instance identifiers are identical. This is not correct and hence requires that the Object.equals method not be called. If, however, the bean class were to subclass another class, you would need to add the method call appendSuper .

Listing 9.29 is an implementation of the equals method using reflection techniques.

Listing 9.29
start example
 public boolean equals( Object o) { return new EqualsBuilder().reflectionEquals( this, o); } 
end example
 

In Listing 9.29, the method reflectionEquals uses reflection to test if two class instances are equal. If you are unsure at all about how to implement the equals method correctly, then using the method reflectionEquals is the simplest and most consistent way to implement the equals method. Using the available reflectionEquals method is not the fastest when you use it; however, you can expect to get the correct answer.

Implementing the Method hashCode

Implementing the hashCode method for a class is as simple as it is for all of the other implementations . Listing 9.30 is a sample implementation.

Listing 9.30
start example
 public int hashCode() { return new HashCodeBuilder( 11, 21) //.appendSuper( super.hashCode()) .append( _iValue) .append( _strValue) .append( _beanValue) .toHashCode(); } 
end example
 

In Listing 9.30, the method hashCode is implemented using the class method HashCodeBuilder . The method appendSuper should be used only if the subclass is not the class Object. The constructor for the class HashCodeBuilder requires two integer values as parameters. The first parameter represents an initial number, and the second parameter represents a multiplier . Both numbers are used to generate a unique identifier. Both numbers should also be unique to the class and be odd, not even. This means that two different class definitions should have two different numbers .

Listing 9.31 shows how the method hashCode can be implemented using reflection.

Listing 9.31
start example
 public int hashCode() { return new HashCodeBuilder( 11, 21).reflectionHashCode( this); } 
end example
 



Applied Software Engineering Using Apache Jakarta Commons
Applied Software Engineering Using Apache Jakarta Commons (Charles River Media Computer Engineering)
ISBN: 1584502460
EAN: 2147483647
Year: 2002
Pages: 109

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net