dtoGen Book

A Short Introduction to dtoGen: a code generation tool

Release 0.5.2

Revision History
Revision 0.22004.10.25
updated on tag parameters (according to dtoGen 0.5.2)
Revision 0.12004.09.28
documentation according to version dtoGen 0.5

Abstract

dtoGen is a library which will help you obtain the data transfer objects out of the domain model objects without writting additional code.


Table of Contents

1. General
Intro
Usage scenarios
Definitions
2. Javadoc Tags
Tags
Class level tag (@dto.gen.class)
Common getter tags
PK getter-level tag (@dto.gen.pk) parameters
Bean property getter tag (@dto.gen.property)
Tag parameter validation
3. Details
Type conversions
Simple conversions
Renaming conversion
Forced type conversion
Conversion tool generation
Injection details
4. Logging and error messages
5. End
Known Issues/TODO
FAQ
Credits

List of Tables

2.1. @dto.gen.class: class level tag
2.2. common parameters for bean property level
2.3. @dto.gen.pk: unique identifier getters level
2.4. @dto.gen.property: bean property getters level

List of Examples

3.1. Domain model object
3.2. Generated DTO
3.3.
3.4.
3.5.
3.6.

Chapter 1. General

dtoGen is a java source generation tool that can ease the development of multi-tier systems by offering a reliable solution to obtain the data transfer objects out of the domain model objects without hand-writting additional code. Using a simple set of javadoc tags, dtoGen provides the possibility to define the whole set of data transfer objects used by your system.

Motivation

Why another tool? There are already many code generation tools (XDoclet, SGen, XSnapshot, just to name a few) that provide the code generation functionality. The reason to create this new tool is that the actual available solutions do not allow to ensemble and/or extract from the domain model graph a very specific part (a good name of this could be snapshot. In the dtoGen notation I will call this: cutout). dtoGen offers a generic solution for this: it offers you the means to define your data transfer objects starting from the domain model in whatever format you need the information (by ensembling together more than one domain model classes, by extracting different info from different domain model classes, etc.).

Intro

dtoGen aims to provide you with a reliable solution for generating data transfer objects by fetching/ensembling only the needed information from your domain model classes [1]. Usually in a N-tier solution the domain model classes reside on the server side. The domain model classes are used for fetching/saving your info from/into a persistence storage (as a relational db, filesystem, etc). According to J2EE guiding rules, a good practice is to use data transfer objects [2] for transfering the domain model info through the layers, this requiring hand-writting of another graph of objects.

dtoGen tries to take this responsibility from the developer and let him concentrate on the real business.

Usage scenarios

I have imagined dtoGen to be used in the following scenarios: [3]

sliceing/cutout

In this scenario you define the data transfer object starting from a single model object and grouping different info from other different model objects. You can include any number of bean properties from any number of model objects. The single limitation is that the main definition of the data transfer object resides in one domain object.

included in version 0.5

inheritance

In this scenario you may define DTOs using inheritance. When using hierarchies of domain model objects, this will help you avoid code duplication inside the generated DTOs. You can define a hierarchy of DTO (using the parameter extends). The DTO hierachy can contain DTOs defined using dtoGen (which are to be generated) (using the parameter ext-mode set to internal) or an existing JavaBean (already defined) (using the parameter ext-mode set to external).

included in version 0.5

synthetic: multiplace definition/usage

In this scenario you are allowed to split the definition of a DTO in multiple places (multiple model objects).

included in version 0.5

external

In this scenario you specify inside the domain model objects that the DTO to be used is an already defined JavaBean object. dtoGen will be responsible with the creation of the conversion tool (specified in the generate-util).

included in version 0.5

You can find out more about these scenarios by looking at the DTO definitions upon which dtoGen is tested. (test directory).

Definitions

I use in this document the following definitions

POJO

this term defines in fact a domain model object. I use the POJO abbrev (Plain Old Java Object) as many system use POJOs to represent their domain model.

Direct conversion

converting a domain model object to a DTO

Inverse conversion

converting a DTO back to its corresponding domain model object(s)

Originator

an originator is a domain model object which is used for the definition of a DTO. The difference from an injector is that the originator declares the DTO, not just declares some properties that must be included in a DTO.

Injector

the injector is a domain model object declaring that some bean properties must be included into a DTO defined by anothe domain model object.



[1] On this document I will use interchangeable domain model classses, domain classes and model classes, all refering to the domain model classes

[2] the abbreviation for data transfer object: DTO.

[3] I hope that the described scenarios cover a large range of possibilities. In case you imagine a new one please drop me an e-mail.

Chapter 2. Javadoc Tags

dtoGen uses a simple system of javadoc tags to help it generate the DTO. It doesn't need anything else - neither at build time, nor at runtime. All you have to do is to include dtoGen javadoc tags in your sources and than let the provided ant task to do its work.

In the following section we will describe in more detail the tags used.

Tags

dtoGen uses 3 different javadoc tags on 2 java code elements:

class level tag

defines the DTO[2] and some options for their generation

accessor/getters level tags for identity fields

define the fields that are able to unique identify the entity [4]

accessor/getters level tags for simple bean property
define a simple bean property that will be included in the DTO[2]

We can imagine that any entity can provide a set of identity fields[4] because any domain model object is uniquely identifiable by some means.

Class level tag (@dto.gen.class)

Table 2.1. @dto.gen.class: class level tag

ParameterDescriptionDefaultRequired (yes/no)
classthe name of the DTO. If fully qualified than dtoGen will extract the package. In case a simple name is used the DTO will be generated in the same package as the actual source.yes
ida unique identifier for DTO. It can be refered from element-type-id and key-type-id parameters. If no value is used than the class parameter value is considered the id. no
def-modeThis parameter specifies the definition type of the DTO. Possible values: internal (specifies that the DTO is defined using dtoGen tags and that the DTO definition occurs only inside one and only one model object), synthetic (specifies that the DTO is defined using dtoGen tags and that the DTO definition is splitted in multiple model objects), external (specifies that the DTO is already defined outside the system) internalno
extendsthe fully qualified name of the parent class of the DTO.no
ext-modePossible values: internal (default) and external. Specifies if the superclass is also defined with dtoGen (internal) or it is an already existing JavaBean (external). internalno
implementscomma separated list of fully qualified names for implemented interfaces. By default dtoGen includes the java.io.Serializableno
generate-tostringflag indicating if a toString() should be generated.falseno
generate-equalsflag indicating if a equals(Object) should be generated. If set to true than a hashCode() method is also generated. Note:We recommend setting this to true.falseno
generate-utilflag indicating if an utility class with the name fqnTool should be generated. Possible values: true, false trueno
util-packagea package name to which the tool class to be generated. This is used only in case def-mode is set to external in order to avoid the generation of the util class in the same package as the external JavaBean. In case this parameter is not used than the package name of the external JavaBean is used for the util class. no
include-codename of a file to be included at the end of the generated DTO source. You must be aware of the fact that the included code is not parsed and so in order to have directly compilable sources you should use fully qualifies class names. In case the def-mode is set to synthetic than code from many files can be included. no

Common getter tags

The parameters used on bean property level share a common set of parameters described here.

Table 2.2. common parameters for bean property level

ParameterDescriptionDefaultRequired (yes/no)
modethe mapping mode. Possible values: simple, collection, array, mapsimpleno
namethe name of the bean property in the DTOinitial nameno
typefully qualified class name of the bean property in DTO or primitive typeinitial typeno
direct-convertora string in the format fqn#method or #method specifying the method responsible for the convertion from the original type to the type defined in type. In the 1st case it must be a static method, while in the second it must be a method available directly on the initial type object.only if type is used
inverse-convertora string in the format fqn#method or #method specifying the method responsible for the convertion from type defined in type to the original type. In the 1st case it must be a static method, while in the second it must be a method available directly on the initial type object.only if type is used
element-typefully qualified class name of a collection or array element or map value element.yes (if mode is collection|array|map)
element-type-idin case the element-type is a POJO which represents the source for multiple DTOs, then specify the id of DTO to be usedyes (only if element type is a POJO which represents the source of more than 1 DTO)
element-convert-typespecifies the mapping for the element-type. This forces the convertion of original type to this type. no
element-direct-convertorequivalent of direct-convertor for element-type to element-convert-type. yes only if element-convert-type is used
element-inverse-convertorequivalent of inverse-convertor used to convert back element-convert-type to element-type.yes only if element-convert-type is used
key-typefully qualified class name of the keys used in map. Note: maps containing as keys different types are not supported.yes (for mode=map)
key-type-idequivalent of element-type-id for map keysyes (only if element type is a POJO which represents the source of more than 1 DTO)
key-convert-typeequivalent of element-convert-type for map keysno
key-direct-convertorequivalent of element-direct-convertor for converting key-type to key-convert-type.yes only if key-convert-type
key-inverse-convertorequivalent for element-inverse-convertor for converting key-convert-type to key-type.yes only if key-convert-type
use-in-tostringspecifies if the bean property should be used when genereting the toString method. Possible values: true, false

This parameter has no effect if the class level parameter generate-tostring is not set.

falseno

PK getter-level tag (@dto.gen.pk) parameters

The PK getter level tag does not require any additional parameters. You can use all common paramters.

Table 2.3. @dto.gen.pk: unique identifier getters level

ParameterDescriptionDefaultRequired (yes/no)
commons parameters

Bean property getter tag (@dto.gen.property)

Table 2.4. @dto.gen.property: bean property getters level

ParameterDescriptionDefaultRequired (yes/no)
commons parameters
dtosthe DTOs to which this property must be perpetuated. Comma separated list of DTO idsyes
use-in-equalsflag marking if this bean property should be used in equals implementation. Possible values: true, falsefalseno

Tag parameter validation

Required parameters

The dto.gen.class tag and dto.gen.property use required parameters. If these are missing than the tag is dismissed and some error/warning message is printed.

toString generation

For the generation of toString method inside a DTO I do the following checks: if there are any java bean properties having the class tag param use-in-tostring set to true than the generate-tostring must also be set to true. In case the generate-tostring is set to true and no java bean properties has the param use-in-tostring set to true than an empty toString method is generated.

equals generation

The validations done for generating equals [5] method inside the DTO are the same as for toString generation.



[4] we will further call this type of fields PK-fields

[5] When generating the equals method, the hashCode method is also generated

Chapter 3. Details

Type conversions

One of the most interesting things done automatically by dtoGen is the deep conversion of type. I will explain here the algorithms used for the type conversions.

Simple conversions

Let's consider the following example domain model object:

Example 3.1. Domain model object

 /**
  * @dto.gen.class class="FooDTO"
  */
 public class Foo {
   private String  name;
   private Bar bar;
   private FooBar country;
   
   // getters and setters
   /**
    * @dto.gen.property dtos="FooDTO"
    */
   public String getName() {
     [...]
   }
   
   /**
    * @dto.gen.property dtos="FooDTO"
    */
   public Bar getBar() {
     [...]
   }
   
   /**
    * @dto.gen.property dtos="FooDTO"
    */
    public FooBar getFooBar() {
      [...]
    }
 }
          

Now, considering that the Bar domain model class defines also a mapping DTO, but the FooBar domain model class does not define a mapping DTO than the resulting FooDTO will be:

Example 3.2. Generated DTO

public class FooDTO implements java.io.Serializable {
  private String name;
  private BarDTO address;
  private FooBar country;
  [...]
}
          

Renaming conversion

Using the name parameter the generated bean property name can be explicitely specified:

Example 3.3. 

/**
 * @dto.gen.class class="FooDTO"
 */
public class Foo {
  private String name;
  
  /**
   * @dto.gen.property dtos="FooDTO" name="personName"
   */
  public String getName() {
    [...]
  }
}
          
then the generated DTO will be:

Example 3.4. 

public class FooDTO implements java.io.Serializable {
  private String personName;
  
  public String getPersonName() {
    [...]
  }
}
          

Forced type conversion

You can force a type conversion using type. Let's consider the following definition:

Example 3.5. 

/**
 * @dto.gen.class class="FooDTO"
 */
public class Foo {
  private Long longValue;
  
  /**
   * @dto.gen.property dtos="FooDTO"
   *                   type="Integer"
   */
  public Long getLongValue() {
    [...]
  }
}
          
will result in the following DTO:

Example 3.6. 

public class FooDTO {
  private Integer longValue;
  
  [...]
}
          

Conversion tool generation

[still to come]

Injection details

[still to come]

Chapter 4. Logging and error messages

Here is a short list with the dtoGen logging messages and warns/errors and their possible causes. An important thing to be known about dtoGen is that it is not restrictive. In case of a failure inside a definition it will be ignored, so if you think something is missing from the generated DTOs please check the messages.

Debug level messages

  • [class] doesn't use dtoGen tags. Class ignored!
    the class level tag @dto.gen.class cannot be found. Further processing is not needed.
  • PK [property_name] used in [class]
    logs that the property_name is declared as PK
  • property [property_name] ignored for PK
    logs that the property_name is not declared as PK
  • property [property_name] used in [class]
    logs that the property_name is declared as property
  • property [property_name] ignored
    logs that the property_name is not declared as a property
  • registering DTOClass [dto_class] with model [model_class]
    logs that the model_class is the originator of dto_class
  • registered SourceUnit [model_class] in [dto_id]
    registers a model class originator or injector in the DTO.

Info level messages

  • [class] doesn't have @dto.gen.class
    the class does not define any DTOs using the class level tag. The processing of the source file is stopped.
  • required parameter <<parameter_name>> not found on @tagname of property_name
    Getter level required parameter is not found. Please consult the list of parameters for details.
  • [class] successfully processed
    the class passed the validation successfully and the information is registered
  • [class] wrong declaration. Model class ignored!
    the class did not passed the validation and will be ignored.

Warn level messages

  • [class] doesn't declare PK fields (@dto.gen.pk not used)
    the class does not define any PK using the getter level tag for PK fields. This may lead to generation problems, as I assume every domain model object must have some fields that are able to uniquely identify an instance.
  • [classname] doesn't define properties (@dto.gen.property not used)
    the classname does not define any bean properties to be included in further DTOs.
  • bean property [property_name] in class [class] use an unknown DTO [dto_id]
    the dto_id used in dtos is not found

Error level messages

  • <<class>> parameter missing in @dto.gen.class tag [class]
    the required class parameter of the class level tag is missing.
  • forced type conversion is missing direct-convertor/inverse-convert on property_name
    When using the forced type conversions (using one of type, element-convert-type or key-convert-type), it is required to define also the corresponding direct-convertor and inverse-convertor There are specific messages for the different forced type conversions.
  • collection/array mode requires element-type parameter on property_name
    for collection and array conversion the parameter element-type is required.
  • map required key-type parameter is missing on property_name
    for map conversion the parameter key-type is required
  • map required element-type parameter is missing on property_name
    for map conversion the parameter element-type is required
  • unknown conversion <<mode>> [mode] on property property_name
    the property property_name declares a wrong conversion mode
  • multiplace definition DTO with different PK. dto_name pk fields not the same with those defined in class. Ignoring information from classSignature.
    in case of synthetic DTO definitions (multiplace DTO definition) the PK fields must be the same.
  • class tag used in model_name doesn't match the reference one. Ignoring source!
    the checking done upon the class level tags extracted from possible multiple model classes fails. The corresponding model source is ignored.

bean property [<<bpi.beanPropName>>] is declared with different element types. IGNORING.

marks the fact that I cannot decide what type should I use for generating the DTO property. This may happen as follows:

  • if the bean property comes from more than one model object it means that the declaring element-types are finally mapped to different types
  • if the bean property comes from more than one model object, the message can tell you that the types used in element-convert-type (so called forced element conversion) are different

bean property [<<bpi.beanPropName>>] is declared with different key types. IGNORING.
see above message
bean property [<<bpi.beanPropName>>] does not have a correct element-type. IGNORING.
both element-type and element-convert-type are not solved (either they are empty or I cannot find a solution to map them).

Chapter 5. End

Known Issues/TODO

This chapter is a simple list of known issues/todos to be solved asap. Each will give also the solution and the schedule.

  • named accessors/mutators
  • PK and property level parameters match all defined dtos, so they do not allow customization per DTO
  • specify for collection types if add/remove individual entities should be generated
    Revision History
    Revision 0.52004.09.25 
    not yet supported
  • remove the runtime dependency on commons-lang for toString, equals and hashCode
    Revision History
    Revision 0.52004.09.25 
    not yet supported
  • fix initial verification of tag parameters. Without this some exception may occur and they are difficult to be trakced down.
  • there is no test other than the full one. I must write down some tests for each step involved.
  • add a type-id for specifying a direct conversion
    Revision History
    Revision 0.32004.09.15 
  • only uni-dimensional arrays are supported
    Revision History
    Revision 0.32004.09.15 
  • enhance error reporting and logging
  • provide a way to include javadoc tags on generated DTOs (in the case these can run through another processing step)

FAQ

This chapter will be written when I will feel it is needed.

Credits

I must thank the following for their contribution:

  • QDox for their great library
  • XSnapshot for giving me a valuable idea.
  • Doclipse for allowing me to rapidly write the tests and providing an easy solution for javadoc tag completion in Eclipse
Many thanks guys. Much appreciation is coming your way directly from me :-).