Skip to main content link. Accesskey S
  • Help
  • HCL Logo
  • HCL Notes and Domino Application Development wiki
  • THIS WIKI IS READ-ONLY. Individual names altered for privacy purposes.
  • HCL Forums and Blogs
  • Home
  • Product Documentation
  • Community Articles
  • Learning Center
  • API Documentation
Search
API Documentation > XPages Extensibility API > Creating and Implementing Complex Types
  • Share Show Menu▼
  • Subscribe Show Menu▼

Recent articles by this author

XPages Extension Library - Dojo Grid & REST Services Controls

This video demonstrates the Dojo Grid and REST Services controls from the XPages Extension Library

XPages Extension Library - Application Layout & Page Navigator Controls

This video demonstrates the Application Layout and Page Navigator controls from the XPages Extension Library

XPages Extension Library - Value Picker & Dojo List TextBox Controls

This video demonstrates the Value Picker and Dojo List TextBox controls from the XPages Extension Library

XPages Extension Library - In Context Editing with the Dialog Control

This video demonstrates "In Context Editing with the Dialog Control" using the XPages Extension Library

XPages Extension Library - Overview

This video demonstration provides an overview of the XPages Extension Library
Community articleCreating and Implementing Complex Types
Added by ~Denise Feznilyynds | Edited by IBM contributor~Sanjay Eklutherettu on September 24, 2010 | Version 3
  • Actions Show Menu▼
expanded Abstract
collapsed Abstract
This article introduces complex types and describes step-by-step how to create and implement them. Complex types are XPages tags that can be assigned as values to properties.
Tags: XPages, 8.5.2, getting started
ShowTable of Contents
HideTable of Contents
  • 1 Introduction
  • 2 Complex Types
    • 2.1 Create the Complex Class
    • 2.2 Register the Complex Tag
    • 2.3 Implement a Property that Allows a Complex Type Value
  • 3 Example Files

Introduction


This article is part of the XPages Extensibility API Developers Guide. It introduces complex types and describes step-by-step how to create and implement them using the XPages Extensibility API.

A complex type represents a tag that can be the value of a property. Examples of native complex types in XPages include:
  • Simple Actions
  • Converters
  • Data Sources
  • Resources
  • Validators

A common usage case of a complex type would be adding a client side JavaScript resource to an XPage. In this case, the script tag is a value of the resources property associated with an XPage.


<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
  <xp:this.resources>
    <xp:script clientSide="true" src="/script.js"></xp:script>
  </xp:this.resources>
</xp:view>


Every tag in XPages represents a definition element in the xsp-config file. These elements define tags, abstract tag superclasses or other named reference-able definitions. These are elements which can contain other elements; i.e. Property and Lower Level elements. For more information, see the "XPages Configuration File Format" reference. The xsp-config file's definition elements include:
  • complex-type
  • component
  • composite-component
  • converter
  • validator

Each definition element specifies their respective *-class element; except composite-component which specifies composite-file instead; this is the corresponding Java class associated with the element. In the case of component, converter and validator; the Java class specified must extend / implement javax.faces.component.UIComponent, javax.faces.convert.Converter and javax.faces.validator.Validator respectively or any subclass thereof. In contrast, by definition the Java class specified by complex-class for the element complex-type cannot extend from the UIComponent class or any its subclasses.

Complex types were invented as an abstraction of converters, validators and any other objects in an XPage that did not correspond to a control (component). However, the converter and validator definitions are declared differently from other complex type definitions for historical reasons; the JavaServer Faces (JSF) faces-config file format allowed for converter and validator definitions but it did not have the concept of a complex-type.

To begin with, you should have an XPages extension like a control which exposes some properties. If not, see the article "Creating a Basic UI Control for XPages" and in particular the section on "Properties".

Complex Types


Given a component with a property that supports complex type values defined as follow:


<property>
  <property-name>foo</property-name>
  <property-class>com.example.complex.Foo</property-class>
</property>


When the component is added to an XPage, by default it is possible to compute the value of the property.


<eg:component foo="#{javascript: new com.example.complex.Foo()}"></eg:component>


However, to specify the property's value as a tag; a complex-type must be defined with a tag-name and complex-class. In order for the complex-type to be associated with the corresponding property, their respective *-class elements (i.e. property-class and complex-class) must both refer to the same Java class. In contrast to computing the value of the property, the defined tag can now be assigned instead.


<eg:component>
  <eg:this.foo>
    <eg:foo></eg:foo>
  </eg:this.foo>
</eg:component>


Creating a complex type involves the following steps:
  1. Create the complex type's Java class
  2. Register the complex type's tag
  3. Implement a property supporting the complex type

Create the Complex Class


Complex types are an abstraction of any object in an XPage that does not correspond to a control; so by definition their Java class cannot extend from UIComponent or any of its subclasses. The complex class should usually be non-abstract and define a public constructor with no arguments. The simplest complex class does not need to implement any interfaces; however if the complex type defines properties then there is a choice about whether to support computed values on those properties.

If supporting computed values, then the complex class should extend from the abstract class com.ibm.xsp.complex.ValueBindingObjectImpl. This provides a base implementation for complex types which need to support computed values. Without explicit handling, computed values give serialization errors when persistence is enabled on the server; the complex type base class provides for this support by implementing the interfaces com.ibm.xsp.binding.ComponentBindingObject and javax.faces.component.StateHolder.


package com.example.complex;

import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import com.ibm.xsp.complex.ValueBindingObjectImpl;

public class ExampleComplex extends ValueBindingObjectImpl {

  private String goo;

  public ExampleComplex() {
  }

  public String getGoo() {
    if (goo != null) {
      return goo;
    }
    ValueBinding vb = getValueBinding("goo");
    if (vb != null) {
      return (String)vb.getValue(getFacesContext());
    }
    return null;
  }

  public void setGoo(String goo) {
    this.goo = goo;
  }
}


If the complex class exposes properties which support computed values, their corresponding getter and setter methods follow the same format as those defined on a component. Finally, the complex class should override the methods saveState and restoreState as necessary to support serialization.


public void restoreState(FacesContext context, Object value) {
  Object[] state = (Object[])value;
  super.restoreState(context, state[0]);
  goo = (String)state[1];
}

public Object saveState(FacesContext context) {
  Object[] state = new Object[2];
  state[0] = super.saveState(context);
  state[1] = goo;
  return state;
}


Register the Complex Tag


All definition elements are registered in an xsp-config file under the root element faces-config. Their definitions have a similar format; each element specifies their ID or type, Java class, tag name and properties. In the case of this example, this is the xsp-config entry for the complex type defined for the Java class created above.


<faces-config>
<faces-config-extension>
  <namespace-uri>http://example.com/xsp/control</namespace-uri>
  <default-prefix>eg</default-prefix>
</faces-config-extension>

<complex-type>
  <description>Example Complex Type</description>
  <display-name>Example Complex Type</display-name>
  <complex-id>com.example.complex.examplecomplex</complex-id>
  <complex-class>com.example.complex.ExampleComplex</complex-class>
  <property>
    <description>Goo</description>
    <display-name>Goo</display-name>
    <property-name>goo</property-name>
    <property-class>java.lang.String</property-class>
  </property>
  <complex-extension>
    <tag-name>cmplx</tag-name>
  </complex-extension>
</complex-type>
</faces-config>


The complex-id is a String identifier used to refer to this complex type definition. By convention, they are prefixed like Java package names to prevent conflicts with other complex types. It can be referenced by base-complex-id to build inheritance trees. If doing so then the tag-name can be omitted which allows the complex-class defined to be either an interface or abstract class. Should the complex-type expose properties, if they do not support computed values then each property should set allow-run-time-binding to false.

Despite being complex types, converters and validators are defined differently for historical reasons. The JSF faces-config file format did define converter and validator elements; however the concept of a complex type, an abstraction of any object on a page that doesn't correspond to a control, was introduced by XPages. Converters and validators are defined similar to complex type; however the converter and validator definition elements are used respectively.


<converter>
  <converter-id>com.example.converter.exampleconverter</converter-id>
  <converter-class>com.example.converter.ExampleConverter</converter-class>
  <converter-extension>
    <tag-name>exampleConverter</tag-name>
  </converter-extension>
</converter>

<validator>
  <validator-id>com.example.validator.examplevalidator</validator-id>
  <validator-class>com.example.validator.ExampleValidator</validator-class>
  <validator-extension>
    <tag-name>exampleValidator</tag-name>
  </validator-extension>
</validator>


Implement a Property that Allows a Complex Type Value


Properties that allow complex type values are implemented similar to any other property exposed by a control. To implement a property which supports complex types for a control, declare a variable using the complex class and define its respective getter and setter methods obeying the JavaBean model for properties and using the JSF get method template.


private ExampleComplex foo;

public ExampleComplex getFoo() {
  if (foo != null) {
    return foo;
  }
  ValueBinding vb = getValueBinding("foo");
  if (vb != null) {
    return (ExampleComplex) vb.getValue(getFacesContext());
  } else {
    return null;
  }
}

public void setFoo(ExampleComplex foo) {
  this.foo = foo;
}


Without explicit handling, computed values and non-serializable objects give serialization errors when persistence is enabled on the server, so the XPages-specific template for computed value serialization must be followed. To serialize a complex type, the static methods saveObjectState and restoreObjectState provided by the StateHolderUtil class should be used in conjunction with the component's saveState and restoreState methods.


public void restoreState(FacesContext context, Object state) {
  Object values[] = (Object[]) state;
  super.restoreState(context, values[0]);
  foo = (ExampleComplex) StateHolderUtil.restoreObjectState(context, this, values[1]);
}

public Object saveState(FacesContext context) {
  Object values[] = new Object[2];
  values[0] = super.saveState(context);
  values[1] = StateHolderUtil.saveObjectState(context, foo);
  return values;
}


Once the property has been implemented, it must be exposed by the control via the xsp-config file as follows. The property-class should be the same as the complex-class, so that the complex-type tag can be used for the foo property. Once the classes are the same, the Designer editor in the All Properties tab will detect that the tag can be set as a value of the property.


<property>
  <description>Foo</description>
  <display-name>Foo</display-name>
  <property-name>foo</property-name>
  <property-class>com.example.complex.ExampleComplex</property-class>
</property>


Finally, despite the property supporting complex types; it is still accessed from the renderer similar to any other property. However, instead of the control returning a primitive or Java class; it returns the defined complex class created previously.


ExampleControl tcomponent = component instanceof ExampleControl ? (ExampleControl) component : null;

ExampleComplex foo;
if (tcomponent != null) {
  foo = tcomponent.getFoo();
} else {
  foo = (ExampleComplex) component.getAttributes().get("foo");
}

if (foo != null) {
  // Output markup
}


Example Files


Download the example files archive. To use this example, create a new application.
In the Package Explorer view, right-click on the new application and select Import - General - Archive File - Next.
Browse to the example files and select Finish. When asked to overwrite existing files, select "Yes To All".

  • Actions Show Menu▼


expanded Attachments (0)
collapsed Attachments (0)
Edit the article to add or modify attachments.
expanded Versions (3)
collapsed Versions (3)
Version Comparison     
VersionDateChanged by              Summary of changes
This version (3)Sep 24, 2010, 11:55:48 AM~Sanjay Eklutherettu  IBM contributor
2Jul 19, 2010, 6:38:55 PM~Phil Fezhipivitchader  IBM contributor
1Sep 24, 2010, 11:42:09 AM~Ted Chukrotheroni  
expanded Comments (0)
collapsed Comments (0)
Copy and paste this wiki markup to link to this article from another article in this wiki.
Go ElsewhereStay ConnectedAbout
  • HCL Software
  • HCL Digital Solutions community
  • HCL Software support
  • BlogsDigital Solutions blog
  • Community LinkHCL Software forums and blogs
  • About HCL
  • Privacy
  • Accessibility