Software development accelerated with Java generics and code templates

Tutorial:

Accelerating software development with Java generics and code templates

By Randall Nagy

TheServerSide.com

Most programmers hate templates at first, but for software developers who are really interested in accelerating application development and creating reusable code that can reduce an application's time to market, learning to love templates is a necessity.

Not only will template syntax make one's eyes cross, but understanding how templates can be used elsewhere, even where they were not officially supported,  can make the head spin, as well. Yet much like anything else, the more one uses templates, the more one likes them. Also known as 'generics' or 'parameterized types', here is an example of the effective use of templates. While Templates have nothing to do with saving or loading data per se,  consider how, simply by using a collection, that we can persist our POJO's without having to resort to SQL databases, property files, or Java serialization:

public class XmlClassIO {
    public String sLastError = "";
    public boolean write(String fileName, T ref) {
        try {
            XMLEncoder encoder = new XMLEncoder(new BufferedOutputStream(
                    new FileOutputStream(fileName))); 
            encoder.writeObject(ref);
            encoder.close();
            return true;
        } catch (Exception ex) {
            this.sLastError = ex.getMessage();
            return false;
        }
    }
    public T read(String fileName) {
        try {
            XMLDecoder decoder = new XMLDecoder(new BufferedInputStream(
                    new FileInputStream(fileName)));
            T result = (T) decoder.readObject();
            decoder.close();
            return result;
        } catch (Exception ex) {
            this.sLastError = ex.getMessage();
            return null;
        }
    }
}
For software developers who are interested in accelerating application development and creating reusable code, learning to love templates is a necessity.

Randall Nagy, Principle Engineer with Soft9000

Single object types and dealing with collections

In the above, most modern Java software developers know that the 'T' in the above code is completely generic. No matter what we choose for the placeholder, be it “E”, “F”, “G”, or something far more descriptive, the location informs us that only a specific, single object can be used with the above XmlClassIO<T> class. While certainly templates can also be defined to reference more than a single T-object, what would happen if the single T-Object in the above template definition was a collection?

The answer is that when 'T' is a placeholder for a standard collection, one that might contain many POJO's, then everything in that collection, be they zero or thousands of objects, can be both saved-to, as well as read-from a file.

Are generics really a big deal?

For folks who routinely wrestle with SQL databases or entity frameworks like Hibernate and MyBATIS, the fact that it only takes a few lines of code to save an any-size-list of objects to a file can be wondrous to behold. Instead of a tough-to-embed tool-chain, the entire file system becomes the database. One simply uses a file-name, rather than a database-table, to manage things.

Indeed, unlike when using SQL Databases, we can certainly store significantly more than one type of object into a single file.

It is perhaps also obvious what will happen when using a Collection, such as an ArrayList<T>, with the above class, we will be creating a well-formed, human editable, XML File, as well. What is not so obvious is how our data members may be represented within that XML. What if someone is not using Java?

By way of an example of what we will find in that XML File, suppose that we want to put together a simple flash-card program (my work-in-progress is called Jackhammer.) Knowing that we will eventually have several type of flash cards, consider the following:

public class FlashTypeOne {
  
    public FlashTypeOne() {
    }

    public FlashTypeOne(String sSubject, String sPrompter, String sResponse) {
        this.Subject = sSubject;
        this.Prompt = sPrompter;
        this.Response = sResponse;
    }

    public String getSubject() {
        return Subject;
    }

    public void setSubject(String Subject) {
        this.Subject = Subject;
    }

    public String getPrompt() {
        return Prompt;
    }

    public void setPrompt(String Prompt) {
        this.Prompt = Prompt;
    }

    public String getResponse() {
        return Response;
    }

    public void setResponse(String Response) {
        this.Response = Response;
    }
}

First and foremost, keep in mind that our Collection requires a collection of POJOs. Why? Because the XML Serializer's use of Reflection to manage getters & setters is precisely why Java Serialization is not required.

Next, adding factory members, such as a static load() as save() would be nice. Since I/O is the real point of our demonstration, both load and save will use that single-object, XML I/O goodness, so lets add two more member functions:

public static List load(File file) {
        ArrayList result = new ArrayList();
        com.soft9000.file.XmlClassIO > io = new XmlClassIO >();
        result = io.read(file);
        return result;
    }
    
    public static boolean save(File file, ArrayList list) {
        com.soft9000.file.XmlClassIO > io = new XmlClassIO >();
        return io.write(file, list);
    }

You might have to read the code twice to see the oddity. Our T-Object is, in reality, another Template. Passing Templates as T-Objects can take some time to get used to seeing, but  the time spent is well worth it.

Finally, by way of a test case, we can add:
 

    public static void main(String ... arg) {
        ArrayList list = new ArrayList();
        list.add(new FlashTypeOne("Test", "One Query", "One Response"));
        list.add(new FlashTypeOne("Test", "Two Query", "Two Response"));
        list.add(new FlashTypeOne("Test", "Three Query", "Three Response"));
        list.add(new FlashTypeOne("Test", "Four Query", "Four Response"));
        list.add(new FlashTypeOne("Test", "Five Query", "Five Response"));
        list.add(new FlashTypeOne("Test", "Six Query", "Six Response"));
        
        File file = new File("BigBadFoo.XML");
        FlashTypeOne.Save(file, list);
        List content = FlashTypeOne.Load(file);
        if(content.containsAll(content) == true) {
            System.out.println("Wow. That XML I/O was easy!");
        }  
   }

Trust me – the above works just peachy.

What is fun next is to look at the type of XML the Serializer provides for us:


<?xml version="1.0" encoding="UTF-8"?> <java version="1.7.0_25" class="java.beans.XMLDecoder">     <object class="java.util.ArrayList">        <void method="add">          <object class="com.soft9000.FlashTypeOne"> <void property="prompt"> <string>One Query</string> </void> <void property="response"> <string>One Response</string> </void> <void property="subject"> <string>Test</string> </void>          </object>         </void> ...

There is no doubt a significant amount of version information in that XML, including the JDK, as well as the class name of the decoder.

At the moment note that unassigned members, as well as automatically assigned default values, will not be part of the XML.

Of course, opinions diverge over the desirability of the omission. Most seem to feel that the exclusion of class-defaults is fairly justifiable. Why? Because, class defaults can change. Yet, over the life-cycle of an object, unofficial conventions, such as isNull()), should ever remain the same.

To travel to the next most feature-observation, notice how the name of our XML object's members are XML attributes, rather than XML tags. Much like the use of a template as template's T-object, lots of folks are surprised by such an encoding.

Lastly, witness also the XML-encoded use of the parent container's 'add' member. The XML encoding represents a 'free' class-defined operation being requested in XML. How cool is that?

The final word on templates

Yet cool or not, the conclusion for many here is, for the moment, that computer-serialized grammars are usually best for computer-only use. Why? Because the history of  XML Languages, like HTML, clearly demonstrate that human beings prefer creating grammars using XML tags, not attributes. Certainly, given the choice, we humans prefer to write our XML quite differently than the XML serializer presently will.

Therefore, and in as much a most of the world is far more into using attributes to describe custom tags, our need to use SAX, DOM, and even Java 7's newfound STAX are still far from over.  For the foreseeable future, the majority of our XML efforts will invariably need to manage far less predictable, grammar-centric, data-tagging activities.

Lastly, if you have never seen how class members can be automatically serialized to XML Tags, then feel free to review ClassIO at Sourceforge.net. While for the moment ClassIO is a humble command line tool, once we provide a few fields, that Javaware demonstrates how to use XML Tags, rather than XML Attributes, to quickly generate reusable code. By way of a bonus, ClassIO is also more about data conversion, than XML. Because XML is not the main purpose of the project, ClassIO generates Classes that can read and write many objects to XML, as well as other popular data formats, via a file.

How has the use of templates improved the quality of your Java code? Let us know.

08 Jul 2013

Related Content

Related Resources