Contact Us 1-800-596-4880

Handling Data Types for Configurable Properties

One integration point between Mule and your connector is the data passing between the connector and Mule ESB, such as when configuring a component. Primitive data types are straightforward; however enumerated types, arrays, and complex types require special handling.

Enumerated Types

DevKit provides an easy way for handling enumerated types. Methods annotated with @Processor or @Source can receive enums as parameters and these can be passed as strings from Mule. It’s also possible to use enumerated types along with java.lang.Collection and java.lang.Map.

Consider the following extension:

@Module(name = "enums")
public class EnumModule {

    private Map<Property, String> properties;

    @Configurable
    private Property myProperty;

    @Processor
    public void setProperties(Map<Property, String> properties) {
        this.properties = properties;
    }

    @Processor
    public String getPropertyValue(Property property) {
        return properties.get(property);
    }

with this enum class:

public enum Property {

    FIRST_NAME, LAST_NAME, ADDRESS
}

Then the following enums types and flows are valid:

<enums:config myProperty="FIRST_NAME"/>
<flow name="setProperties">
    <enums:set-properties>
        <enums:properties>
            <enums:property key="FIRST_NAME">Federico</enums:property>
            <enums:property key="LAST_NAME">Recio</enums:property>
        </enums:properties>
    </enums:set-properties>
</flow>
<flow name="getPropertyValue">
    <enums:get-property-value property="LAST_NAME"/>
</flow>

How It Works

Under the hood, DevKit generates a Transformer for all the enumerated types that appear as parameters of @Processor and @Source methods, or any instance field annotated with @Configurable. So when a string is entered in the xml for an enumerated type, the enum constant with the specified name is passed to the method or assigned to the field.

The generated schema file also adds restrictions so that only matching enumerated values can be used in the xml. For example, since the possible values for the Property enum are FIRST_NAME, LAST_NAME, and ADDRESS then the following is not valid and the validation of the schema will fail:

<flow name="getPropertyValue">
    <enums:get-property-value property="COUNTRY"/>
</flow>

Collections

DevKit provides a simple way to handle java.util.Collection `and `java.util.Map types, whether they appear in @Configurable fields, or as parameters of @Processor or @Source methods. DevKit also allows more complex scenarios where types are nested such as Map<String, List<String>> or List<Map<String, Object>>.

There are two ways to handle these types from Mule.

  • Declare the elements explicitly.

  • Pass a reference to the elements.

    Note: all the examples and explanations on this page are valid both for @Module and @Connector classes.

Collection Examples

Consider the following custom Mule Module:

import org.mule.api.annotations.Configurable;
import org.mule.api.annotations.Module;
import org.mule.api.annotations.Processor;
import org.mule.api.annotations.param.Optional;

import java.util.List;
import java.util.Map;

@Module(name = "collection")
public class CollectionModule {

    @Configurable
    @Optional
    private List<String> strings;

    @Configurable
    @Optional
    private Map<String, String> mapStrings;

And these Spring beans:

<spring:bean id="objectA" class="java.lang.String">
        <spring:constructor-arg value="ObjectA"/>
    </spring:bean>

    <spring:bean id="objectB" class="java.lang.String">
        <spring:constructor-arg value="ObjectB"/>
    </spring:bean>

    <spring:bean id="list" class="org.springframework.beans.factory.config.ListFactoryBean">
        <spring:property name="sourceList">
            <spring:list>
                <spring:ref bean="objectA"/>
                <spring:ref bean="objectB"/>
            </spring:list>
        </spring:property>
    </spring:bean>

You can configure the Module any of the following ways.

  • Declare the list elements explicitly.

    <collection:config>
            <collection:strings>
                <collection:string>MuleSoft</collection:string>
                <collection:string>FTW</collection:string>
            </collection:strings>
        </collection:config>
  • Declare the map elements explicitly.

    <collection:config>
            <collection:map-strings>
                <collection:map-string key="a">MuleSoft</collection:map-string>
                <collection:map-string key="b">FTW</collection:map-string>
            </collection:map-strings>
        </collection:config>
  • Like the previous map, use the tag names (a and b) as keys.

    <collection:count-map-of-strings config-ref="configC">
                <collection:map-strings>
                    <collection:a>mulesoft</collection:a>
                    <collection:b>ftw</collection:b>
                </collection:map-strings>
            </collection:count-map-of-strings>
  • Declare one element explicitly and use a reference for the other element.

    <collection:config>
            <collection:strings>
                <collection:string>MuleSoft</collection:string>
                <collection:string value-ref="objectA"/>
            </collection:strings>
        </collection:config>
  • Instead of declaring the elements of the list, pass a reference to a bean of the same type.

    <collection:config name="configA">
            <collection:strings ref="list" />
        </collection:config>

Nested Collections

Now consider the following @Processor method.

@Processor
    public void mapOfLists(Map<String, List<String>> map) {

The generated message processor can be invoked as follows.

<collection:map-of-lists>
            <collection:map>
                <collection:map key="key1" value-ref="list" />
                <collection:map key="key2" value-ref="#[map-payload:anotherList]" />
            </collection:map>
        </collection:map-of-lists>

Instead of passing the values of the map by reference, the map itself can also be a reference:

<collection:map-of-lists>
            <collection:map ref="#[map-payload:myMap]" />
        </collection:map-of-lists>

Complex Types

DevKit supports the following types:

  • int

  • float

  • long

  • byte

  • short

  • double

  • boolean

  • char

  • java.lang.Integer

  • java.lang.Float

  • java.lang.Long

  • java.lang.Byte

  • java.lang.Short

  • java.lang.Double

  • java.lang.Boolean

  • java.lang.Character

  • java.lang.String

  • java.math.BigDecimal

  • java.math.BigInteger

  • java.util.Date

  • java.lang.Class

  • java.net.URL

  • java.net.URI

You can pass other types by reference.

@Processor
public void receiveAComplexType(MyComplexType myComplexType) { ... }

DevKit enables you to use such processors, especially when Anypoint DataMapper uses the module. DataMapper-friendly modules pass information in beans, since DataMapper can extract metadata from both a Java bean and the XML. DevKit also standardizes the way Mule passes references.

Complex Type Construction

When an @Processor method receives a complex type, DevKit deconstructs the object then constructs a schema that can be used to reconstruct that object. This lets you represent complex type objects with concise, intuitive XML. For example:

<ns:receive-a-complex-type>
    <ns:my-complex-type color="red"/>
</ns:receive-a-complex-type>

You can use the following annotations inside the complex type definition to control schema generation:

  • @Optional

  • @Default

Further, a complex type can have inner lists or maps of other complex types.

Ignoring Fields in a Complex Type

The @Ignore annotation tells DevKit to ignore a field inside a complex object.

public class MyComplexType
{
    private String color;

    @Ignore
    private String description;
}

@Processor
public void receiveAComplexType(MyComplexType myComplexType) { ... }

DevKit omits the description field from the generated schema. For example, the snippet below is invalid, because the @Ignored description attribute is not part of the generated schema. For DevKit’s purposes, at the XML level this element does not have a description attribute.

<ns:receive-a-complex-type>
    <ns:my-complex-type color="red" description=""/>
</ns:receive-a-complex-type>

Passing List and Map Objects by Reference

DevKit standardizes the way to pass objects by reference. List and Map objects can be passed by reference in a ref attribute in a child element, as in the following examples.

@Processor
public void receiveAList(List<String> strings) { ... }
<ns:receive-a-list>
  <ns:strings ref="#[payload]"/>
</ns:receive-a-list>

In DevKit, passing a complex object also uses a ref attribute in a child element.

<ns:receive-a-complex-type>
    <ns:my-complex-type ref="#[payload]"/>
</ns:receive-a-complex-type>