CroftSoft / Library / Tutorials

Enumerated Accessors

David Wallace Croft

2007 Jun 29 Fri


Abstract. Adding new data fields to a Java class can be simplified by using enumerated types as arguments to accessor and mutator methods.

This tutorial is an update of the "Persistent Data" chapter in my book Advanced Java Game Programming. Data management and persistence are simplified by using new features that have been added to the Java programming language such as enumerated types and JAXB.

    package com.croftsoft.apps.ajgp.data;

    /*********************************************************************
    * Example of enumerated accessors.
    *
    * @since
    *   2007-06-28
    * @author
    *   <a href="http://www.CroftSoft.com/">David Wallace Croft</a>
    *********************************************************************/

    public interface  EnumData
    ////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////
    {
      
    public enum  EnumInteger
    {
      HEALTH,
      WEALTH,
      WISDOM,
    }
    
    public enum  EnumString
    {
      CHARACTER_NAME,
      PLAYER_NAME,
      USER_ID,
    }

    ////////////////////////////////////////////////////////////////////////
    // accessor methods
    ////////////////////////////////////////////////////////////////////////

    public Integer  get ( EnumInteger  enumInteger );
    
    public String   get ( EnumString   enumString  );

    ////////////////////////////////////////////////////////////////////////
    // mutator methods
    ////////////////////////////////////////////////////////////////////////

    public void  set (
      EnumInteger  enumInteger,
      Integer      value );
    
    public void  set (
      EnumString  enumString,
      String      value );

    ////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////
    }

Please note in the preceding code listing for interface EnumData that the accessor and mutator methods (getters and setters) have enumerated type arguments. Instead of calling getHealth(), one calls get(EnumInteger.HEALTH). Adding new data fields as your program grows is as simple as adding a new constant to the list of enumerated types. Strong compile-time typing is ensured since the enumerated types are grouped by data type.

    package com.croftsoft.apps.ajgp.data;
    
    import java.util.*;
    import javax.xml.bind.annotation.*;

    import com.croftsoft.core.lang.NullArgumentException;

    /*********************************************************************
    * Bean implementation of interface of EnumData.
    *
    * @since
    *   2007-06-28
    * @author
    *   <a href="http://www.CroftSoft.com/">David Wallace Croft</a>
    *********************************************************************/

    @XmlRootElement
    public final class  EnumDataBean
      implements EnumData
    ////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////
    {
      
    private Map<EnumInteger, Integer>  integerMap;
    
    private Map<EnumString,  String>   stringMap;
      
    ////////////////////////////////////////////////////////////////////////
    // constructor methods
    ////////////////////////////////////////////////////////////////////////
      
    public  EnumDataBean ( )
    ////////////////////////////////////////////////////////////////////////
    {
      // a no-argument constructor for JAXB conversion
    }
      
    ////////////////////////////////////////////////////////////////////////
    // interface EnumData accessor methods
    ////////////////////////////////////////////////////////////////////////

    public Integer  get ( final EnumInteger  enumInteger )
    ////////////////////////////////////////////////////////////////////////
    {
      NullArgumentException.check ( enumInteger );
      
      return integerMap == null ? null : integerMap.get ( enumInteger );
    }
    
    public String  get ( final EnumString  enumString )
    ////////////////////////////////////////////////////////////////////////
    {
      NullArgumentException.check ( enumString );
      
      return stringMap == null ? null : stringMap.get ( enumString );
    }

    ////////////////////////////////////////////////////////////////////////
    // interface EnumData mutator methods
    ////////////////////////////////////////////////////////////////////////

    public void  set (
      final EnumInteger  enumInteger,
      final Integer      value )
    ////////////////////////////////////////////////////////////////////////
    {
      NullArgumentException.check ( enumInteger );
      
      if ( integerMap == null )
      {
        integerMap
          = new EnumMap<EnumInteger, Integer> ( EnumInteger.class );
      }
      
      if ( value == null )
      {
        integerMap.remove ( enumInteger );
      }
      else
      {
        integerMap.put ( enumInteger, value );
      }
    }
    
    public void  set (
      final EnumString  enumString,
      final String      value )
    ////////////////////////////////////////////////////////////////////////
    {
      NullArgumentException.check ( enumString );
      
      if ( stringMap == null )
      {
        stringMap = new EnumMap<EnumString, String> ( EnumString.class );
      }
      
      if ( value == null )
      {
        stringMap.remove ( enumString );
      }
      else
      {
        stringMap.put ( enumString, value );
      }
    }

    ////////////////////////////////////////////////////////////////////////
    // JAXB accessor methods
    ////////////////////////////////////////////////////////////////////////
    
    public Map<EnumInteger, Integer>  getIntegerMap ( )
    ////////////////////////////////////////////////////////////////////////
    {
      return integerMap;
    }
    
    public Map<EnumString, String>  getStringMap ( )
    ////////////////////////////////////////////////////////////////////////
    {
      return stringMap;
    }
    
    ////////////////////////////////////////////////////////////////////////
    // JAXB mutator methods
    ////////////////////////////////////////////////////////////////////////
    
    public void  setIntegerMap (
      final Map<EnumInteger, Integer>  integerMap )
    ////////////////////////////////////////////////////////////////////////
    {
      this.integerMap = integerMap;
    }
    
    public void  setStringMap (
      final Map<EnumString, String>  stringMap )
    ////////////////////////////////////////////////////////////////////////
    {
      this.stringMap = stringMap;
    }
    
    ////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////
    }

The preceding code listing for EnumDataBean is a bean implementation of interface EnumData. A bean implementation requires a no-argument constructor and a get/set method pair for each data field. In this case the data fields are integerMap and stringMap. Using a bean implementation permits automatic conversion to XML using JAXB.

    package com.croftsoft.apps.ajgp.data;
    
    import java.io.*;
    import javax.xml.bind.*;

    import com.croftsoft.apps.ajgp.data.EnumData.*;
    
    /*********************************************************************
    * Test of enumerated accessors.
    *
    * @since
    *   2007-06-28
    * @author
    *   <a href="http://www.CroftSoft.com/">David Wallace Croft</a>
    *********************************************************************/

    public final class  EnumDataTest
    ////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////
    {
      
    public static void  main ( final String [ ]  args )
      throws Exception
    ////////////////////////////////////////////////////////////////////////
    {
      final EnumData  enumData = new EnumDataBean ( );
      
      enumData.set ( EnumInteger.HEALTH, new Integer ( 10 ) );
      
      enumData.set ( EnumInteger.WEALTH, new Integer ( 99 ) );
      
      enumData.set ( EnumInteger.WISDOM, new Integer ( 18 ) );
      
      enumData.set ( EnumString.USER_ID, "croft" );
      
      enumData.set ( EnumString.PLAYER_NAME, "David Wallace Croft" );
      
      enumData.set ( EnumString.CHARACTER_NAME, "Enoch the Elf" );
      
      // convert from bean object to XML
      
      final JAXBContext  jaxbContext
        = JAXBContext.newInstance ( EnumDataBean.class );
      
      final Marshaller  marshaller = jaxbContext.createMarshaller ( ); 
      
      marshaller.setProperty (
        Marshaller.JAXB_FORMATTED_OUTPUT,
        Boolean.TRUE );

      final ByteArrayOutputStream  byteArrayOutputStream
        = new ByteArrayOutputStream ( );

      marshaller.marshal ( enumData, byteArrayOutputStream );
      
      final byte [ ]  byteArray = byteArrayOutputStream.toByteArray ( ); 
      
      System.out.println ( new String ( byteArray, "UTF-8" ) );
      
      // convert from XML to bean object
      
      final Unmarshaller  unmarshaller = jaxbContext.createUnmarshaller ( );
      
      final EnumData  enumData2
        = ( EnumData ) unmarshaller.unmarshal (
          new ByteArrayInputStream ( byteArray ) );
      
      System.out.println ( "" );
      
      for ( final EnumInteger  enumInteger : EnumInteger.values ( ) )
      {
        System.out.println ( enumData2.get ( enumInteger ) );
      }
      
      for ( final EnumString  enumString : EnumString.values ( ) )
      {
        System.out.println ( enumData2.get ( enumString ) );
      }      
    }
    
    ////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////
    }

The preceding code listing for EnumDataTest demonstrates setting the data values via the enumerated type argument mutator methods (enumerated mutators), automatically converting the bean object into XML, converting it back from XML into an object again, and iterating over the data using the enumerated accessors. The following listing shows the output.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<enumDataBean>
    <integerMap>
        <entry>
            <key>HEALTH</key>
            <value>10</value>
        </entry>
        <entry>
            <key>WEALTH</key>
            <value>99</value>
        </entry>
        <entry>
            <key>WISDOM</key>
            <value>18</value>
        </entry>
    </integerMap>
    <stringMap>
        <entry>
            <key>CHARACTER_NAME</key>
            <value>Enoch the Elf</value>
        </entry>
        <entry>
            <key>PLAYER_NAME</key>
            <value>David Wallace Croft</value>
        </entry>
        <entry>
            <key>USER_ID</key>
            <value>croft</value>
        </entry>
    </stringMap>
</enumDataBean>


10
99
18
Enoch the Elf
David Wallace Croft
croft

You can see how as your program grows, this permits you to easily add data fields with automatic XML persistence simply by adding a new enumerated type constant to your interface. Instead of a get/set method pair for each data field such as getHealth()/setHealth(), you now only need to implement a get/set pair for each data type such as get(EnumInteger)/set(EnumInteger). Strong compile-time typing is preserved as the return type of an enumerated accessor is indicated by the enumerated type argument.

 
 
 
CroftSoft
 
 
About
Library
-Books
-Code
-Courses
-Links
-Media
-Software
-Tutorials
People
Portfolio
Update
 
 
Google
CroftSoft Web

 

Creative Commons License
© 2007 CroftSoft Inc.
You may copy this webpage under the terms of the
Creative Commons Attribution License.