Defining a new tax identification number data type
The following examples illustrates the steps involved in defining a new data type and using it. The example defines a new data type for Tax Identification Number objects, called TaxID. The data type has one required property, the name of the property on the context object. This property, countryProperty, identifies which country is in context for validating the data.
This example contains the following steps:
Step 1: Register the data type
About this task
To register a new data type, create a file named XXX.dti, with XXX as the name of the new data type. In this case, create a file named TaxID.dti. To do this:
Procedure
- In Guidewire Studio, in the Project tool window, navigate to .
- Right-click datatypes, and then click .
- Enter TaxID.dti as the file name. This action creates an empty data type file and places it in the datatypes folder.
-
Enter the following text in the file:
<?xml version="1.0"?> <DataTypeDef xmlns="http://guidewire.com/datatype" type="gw.newdatatypes.TaxIDDataTypeDef" valueType="java.lang.String"> <ParameterDef name="countryProperty" desc="The name of a property on the owning entity, whose value contains the country with which to validate and format values." required="true" type="java.lang.String"/> </DataTypeDef>The root element of TaxID.dti is
<DataTypeDef>and the namespace ishttp://guidewire.com/datatype.This example defines the following:
data type name
TaxIDvalue type
Stringparameter
contactTypeimplementation type
gw.newdatatypes.TaxIDDataTypeDef
What to do next
After completing this task, complete Step 2: Implement the IDataTypeDef Interface.
See also
- For details on the attributes and elements relevant to the data type definition, see The PolicyCenter data model.
Step 2: Implement the IDataTypeDef Interface
Before you begin
About this task
The implementation class that you create to handle the TaxID data type must do the following:
- It must implement the
gw.datatype.def.IDataTypeDefinterface. - It must have a no-argument constructor.
- It must have a property for each of the data type parameters.
For example, suppose that you have a new data type that has a String parameter named someParameter. The implementation class (specified in the type attribute) must define a writable property named someParameter, so that the data type factory can pass the argument values to the implementation. The implementation can then use the parameters in the implementation of the various handlers, which are:
gw.datatype.handler.IDataTypeConstraintsHandlergw.datatype.handler.IDataTypePersistenceHandlergw.datatype.handler.IDataTypePresentationHandler
Class TaxIDDataTypeDef
For our example data type, the gw.newdatatypes.TaxIDDataTypeDef class looks similar to the following. To create this file, first create the package, then the class file, in the Studio Classes folder.
package gw.newdatatypes
uses gw.datatype.def.IDataTypeDef
uses gw.datatype.handler.IDataTypeConstraintsHandler
uses gw.datatype.handler.IDataTypePresentationHandler
uses gw.datatype.handler.IDataTypePersistenceHandler
uses gw.lang.reflect.IPropertyInfo
uses gw.datatype.handler.IDataTypeValueHandler
uses gw.datatype.def.IDataTypeDefValidationErrors
uses gw.datatype.impl.VarcharPersistenceHandler
uses gw.datatype.impl.SimpleValueHandler
class TaxIDDataTypeDef implements IDataTypeDef {
private var _countryProperty : String as CountryProperty
override property get ConstraintsHandler() : IDataTypeConstraintsHandler {
return new TaxIDConstraintsHandler(CountryProperty)
}
override property get PersistenceHandler() : IDataTypePersistenceHandler {
return new VarcharPersistenceHandler(/* encrypted */ false,
/* trimWhitespace */ true,
/* size */ 30)
}
override property get PresentationHandler() : IDataTypePresentationHandler {
return new TaxIDPresentationHandler(CountryProperty)
}
override property get ValueHandler() : IDataTypeValueHandler {
return new SimpleValueHandler(String)
}
override function validate(prop : IPropertyInfo, errors : IDataTypeDefValidationErrors) {
// Check that the CountryProperty names an actual property on the owning type, and that
// the type of the property is typekey.Country.
var countryProp = prop.OwnersType.TypeInfo.getProperty(CountryProperty)
if (countryProp == null) {
errors.addError("Property \"" + CountryProperty + "\" does not exist on type " +
prop.OwnersType)
} else if (not typekey.Country.Type.isAssignableFrom(countryProp.Type)) {
errors.addError("Property " + countryProp + " does not resolve to a " + typekey.Country)
}
}
}
Note that the class defines a property named CountryProperty, which the system calls to pass the
countryProperty parameter. Also notice how the implementation reads the value of CountryProperty as its
constructs its constraints and presentation handlers. Guidewire guarantees to fill the implementation parameters
before calling the handlers.
In the example code, the class refers to constraints and presentation handlers created specifically for this data
type. However, it also reuses a Guidewire-provided persistence handler, the VarcharPersistenceHandler. You
do not usually need to create your own persistence handler, as Guidewire defines persistence handlers for all the
basic database column types.
What to do next
After completing this task, complete Step 3: Implement the data type aspect handlers.
Step 3: Implement the data type aspect handlers
Before you begin
About this task
As you define a new data type, it is possible (actually likely) that you need to define one or more handlers for the data type. These handler interfaces are different than the Data Type API interfaces. For example, clients that use the Data Type API use the following:
gw.datatype.IConstrainedDataTypeHowever, if you define a new data type, you must implement the following:
gw.datatype.handler.IDataTypeConstraintsHandlerThis separation of interfaces allows the definition of a caller-friendly interface for data type clients and a implementation-friendly interface for data type designers.
The example data type defines a handler for both constraints and presentation.
Class TaxIDConstraintsHandler
This class looks similar to the following:
package gw.newdatatypes
uses gw.datatype.handler.IStringConstraintsHandler
uses gw.lang.reflect.IPropertyInfo
uses java.lang.Iterable
uses java.lang.Integer
uses java.lang.CharSequence
uses gw.datatype.DataTypeException
class TaxIDConstraintsHandler implements IStringConstraintsHandler {
var _countryProperty : String
construct(countryProperty : String) {
_countryProperty = countryProperty
}
override function validateValue(ctx : Object, prop : IPropertyInfo, value : Object) {
var country = getCountry(ctx)
switch (country) {
case "US": validateUSTaxID(ctx, prop, value as java.lang.String)
break
// other countries ...
}
}
override function validateUserInput(ctx : Object, prop : IPropertyInfo, strValue : String) {
validateValue(ctx, prop, strValue)
}
override function getConsistencyCheckerPredicates(columnName : String) : Iterable<CharSequence> {
return {}
}
override function getLoaderValidationPredicates(columnName : String) : Iterable<CharSequence> {
return {}
}
override function getLength(ctx : Object, prop : IPropertyInfo) : Integer {
var country = getCountry(ctx)
switch (country) {
case "US": return ctx typeis Person ? 11 : 10
// other countries ...
}
return null
}
private function getCountry(ctx : Object) : Country {
return ctx[_countryProperty] as Country
}
private function validateUSTaxID(ctx : Object, prop : IPropertyInfo, value : String) {
var pattern = ctx typeis Person ? "\\d{3}-\\d{2}-\\d{4}" : "\\d{2}-\\d{7}"
if (not value.matches(pattern)) {
throw new DataTypeException("${value} does not match required pattern ${pattern}", prop,
"Validation.TaxID", { value })
}
}
}
Class TaxIDPresentationHandler
This class looks similar to the following:
package gw.newdatatypes
uses gw.lang.reflect.IPropertyInfo
uses gw.datatype.handler.IStringPresentationHandler
class TaxIDPresentationHandler implements IStringPresentationHandler {
private var _countryProperty : String
construct(countryProperty : String) {
_countryProperty = countryProperty
}
function getEditorValue(ctx : Object, prop : IPropertyInfo) : Object {
return null
}
override function getDisplayFormat(ctx : Object, prop : IPropertyInfo ) : String {
return null
}
override function getInputMask(ctx : Object, prop : IPropertyInfo) : String {
switch (getCountry(ctx)) {
case "US": return ctx typeis Person ? "###-##-####" : "##-#######"
// other countries ...
}
return null
}
override function getPlaceholderChar(ctx : Object, prop : IPropertyInfo) : String {
return null
}
private function getCountry(ctx : Object) : Country {
return ctx[_countryProperty] as Country
}
}
Notice how each of these handlers makes use of the context object in order to determine the type of input mask and validation string to use.
