Skip to content

Toro Cloud Dev Center


Gloop object converters

To make Gloop as easy as possible to use, Gloop tries to automatically convert certain objects to other types while your services are running. For example, if you have a String and need to map it to a number (such as Integer, BigDecimal, or Float), Gloop will try to do the conversion for you.

When Gloop is told to map (or set) a value to a Gloop object, it iterates through the built-in converters to find one that supports the conversion necessary.

Below is a list of converters that are built-in to Gloop, and what they support.

AssignableFromConverter

This converter simply checks whether the source is either the same as or is a superclass or superinterface of the class or interface represented by the target. If it is, then no conversion needs to take place and the source value is used directly. This is basically the same as the following in Java code:

1
2
if ( targetClass.isAssignableFrom( sourceValue.getClass() ) )
   return sourceValue;

NumberConverter

This converter tries to convert CharSequence objects, primitives (int, short, float, double, long, byte, char) and Number objects to other Number objects, char, or Character objects. When converting to char or Character objects, toString() is called on the source object and the first character of the resulting string is used as the value. If the toString() method returns null or an empty string, 0 is returned.

IterableConverter

This converter tries to convert Gloop, Iterable, Iterator, and Map objects to Iterable, Iterator, Set, or SortedSet objects. If the source is a Gloop object and it is not an array, the target object will only have one entry: the Gloop object's value.

ArrayConverter

This converter re-uses all the other built-in converters to try and convert Java object arrays, and collections to other arrays and collections. It also has the ability to create Gloop objects from arrays if there is a converter that supports converting the type in the array to the target type. Keeping in mind that this converter handles the conversion of arrays to non-arrays, it also has the ability to convert byte arrays to a String.

GloopObjectMapConverter

This converter tries to convert Gloop objects to Map objects and Map objects to GloopModel objects.

CharSequenceToClassConverter

If the source is an instance of CharSequence and the target is a Class object, this will try and instantiate an instance of the class using the value of the CharSequence as the class name.

CharSequenceToClosureConverter

If the source is an instance of CharSequence and the target is a Closure object, this converter will try and compile the CharSequence to a Groovy closure.

CharSequenceToEnumConverter

If the source is an instance of CharSequence and the target is an enum value, this will try to convert the CharSequence value to the enum value.

CharSequenceToRunnableConverter

If the source is an instance of CharSequence and the target is a Runnable object, this converter will try and compile the CharSequence to a Java Runnable.

DateCalendarConverter

This converter does its best to handle Java Date objects in Gloop for you. It accepts:

... and tries to convert these into:

The DateCalendarConverter first tries to convert the source to a java.util.Date object, then converts that to the target (if it needs to). Below is a list that explains how it tries to convert the CharSequence and Number source objects to a java.util.Date:

  1. First, CharSequence objects are checked whether they are in any of the following formats (examples are after the hyphen):
    • YYYY-MM-dd'T'HH:mm:ss'Z' - 1994-11-05T08:15:30Z
    • YYYY-MM-dd'T'HH:mm:ssZ - 1994-11-05T08:15:30-05:00
    • YYYY-MM-dd'T'HH:mm:ss.SSSZ - 2013-12-14T01:55:33.412Z
    • EEE MMM dd HH:mm:ss zzz yyyy - Sun Dec 30 00:00:00 PHT 2007
    • yyyy-MM-dd hh:mm:ss.S - 2007-12-30 00:00:00.0
  2. Next, if the CharSequence is now or now() then the current time is used.
  3. If the source object is a CharSequence whose value is a number or the source object is a Number, then it's converted to a long and a new Date is created from it.
  4. If the CharSequence is an XML formatted date, a new Date is created from it.
  5. If the CharSequence is an XML formatted date and time, a new Date is created from it.
  6. If the CharSequence is an XML formatted time, a new Date is created from it.

Custom date formats

If the built-in Gloop DateCalendarConverter doesn't recognize the date formats you use, you can add custom date format patterns to your date objects. The date formats here are used before Gloop tries to use the DateCalendarConverter. To write the values back in your custom format, use the Output Expression in your date objects.

ObjectToBooleanConverter

This converts objects to boolean objects. If the source object is a Number, then this will return true if the number is greater than 0. If the source object is a CharSequence, then the toString() value is checked to see whether it equals true (case insensitive).

ObjectToConstructorConverter

This looks at target classes and checks whether the class has a single argument constructor whose parameter type is the same as the source object. If the target class has a matching constructor, it's used to instantiate the target object.

CharSequenceToFileConverter

This converter creates File objects from CharSequence objects. The value of the CharSequence is used as the filename of the File.

InputStreamConverter

This converter is what Gloop uses when it needs to convert various types of input-based I/O objects and byte arrays to others. It can convert any of these:

to:

OutputStreamConverter

This converter is what Gloop uses when it needs to convert various types of output-based I/O objects to others. It can convert any of these:

to:

StreamToContentConverter

Similar to the InputStreamConverter except this reads all available input data to either CharSequence, StringBuffer objects, or byte arrays.

ContentToStreamConverter

This converter tries to read from various objects that contain data and convert them to commonly used Java objects for reading data. This converter converts from:

to:

ObjectToCharSequenceConverter

This is the last converter that Gloop uses. It simply converts:

to:

Adding custom converters

Gloop allows you to add custom converters. Simply call GloopObjectConverterManager#registerConverter(GloopObjectConverter, int)1. The first argument is the converter to register in Gloop and the second argument is where in the list of converters you want yours to go. The GloopObjectConverter2 interface looks as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package io.toro.gloop.object.converter;

interface GloopObjectConverter {

    /**
     * @return {@code true} if the converter supports the conversion
     */
    boolean supports(Class from, Class to);


    /**
     * Perform the actual conversion.
     * @throws ClassCastException if it cannot do the conversion.
     */
    Object convertTo(Object from, Class to);

}

When you register your own converter, you will be able to bridge the gap between your Java and Gloop code! Martini uses converters heavily in most of the utility methods under the core package. Your converter will be used by Gloop automatically when it's required, and this means you can reuse legacy code that accepts your beans in Gloop by simply mapping between Gloop and your code! With your own converter, code like this will also be possible:

1
2
3
4
5
// Gloop to POJO.
MyCustomPojo myCustomPojo = (MyCustomPojo) gloopModel.getValue(MyCustomPojo.class);

// POJO to Gloop.
gloopModel.setValue(myCustomPojo);

Below is an example implementation that registers a custom converter. It converts a custom POJO at the bottom of the code to Gloop models and back:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import io.toro.gloop.object.converter.GloopObjectConverter;
import io.toro.gloop.object.converter.GloopObjectConverterManager;
import io.toro.gloop.object.property.GloopModel;

public class CustomPojoConverter implements GloopObjectConverter {

    @Override
    public boolean supports(Class from, Class to) {
        if (to.isAssignableFrom(GloopModel.class) && MyCustomPojo.class.isAssignableFrom(from))
            return true;
        else if (to.isAssignableFrom(MyCustomPojo.class) && GloopModel.class.isAssignableFrom(from))
            return true;
        return false;
    }

    @Override
    public Object convertTo(Object from, Class to) {
        if (from instanceof GloopModel) {
            // Convert Gloop Model to my custom POJO.
            return myPojo;
        }
        // Convert my POJO to a Gloop Model.
        return new GloopModel();
    }

    // Register this method as a startup service! ;)
    public static void register() {
        // Add to the end of the converters list.
        GloopObjectConverterManager.registerConverter(new CustomPojoConverter());
    }

}

Startup services

Configure your Martini package to call the register() method as a startup service. That way, Martini will call your converter-registering code as your package starts!


  1. Complete signature is io.toro.gloop.object.converter.GloopObjectConverterManager#registerConverter(io.toro.gloop. object.converter.GloopObjectConverter, int)

  2. Complete namespace is io.toro.gloop.object.converter.GloopObjectConverter