Custom Types

Converting between Excel types and Java type can result in a lot of repeated code. It can be more convenient to be able to write the conversion code once and have Jinx call it automatically.

One use case for this is when you have functions that take a enum, and rather than wrapping these functions so that they take a string and then converting the string to the enum it is possible to have Jinx do that for you.

With Jinx you can register conversion functions for argument and return value types. These conversion functions convert between the standard types that Jinx knows about and your own custom types.

Custom Argument Converters

Argument converters are methods annotated with the @ExcelArgumentConverter annotation. When a function is called and an argument can’t be simply converted from the Excel type, Jinx will look for a suitable argument converter to use.

import com.exceljava.jinx.ExcelArgumentConverter;

class MyEnumConverter {
    @ExcelArgumentConverter
    public static MyEnum enumFromString(String value) {
        if (value.equals("X")) {
            return MyEnum.X;
        } else if (value.equals("Y")) {
            return MyEnum.X;
        }
        // etc...
        throw new IllegalArgumentException(String.format("Unexpected value '%s'", value));
    }
}

This class has to be added to the list of classes for Jinx to load, and once it is methods that take MyEnum can be used without any additional code.

import com.exceljava.jinx.ExcelFunction;

class MyEnumFunction {
    @ExcelFunction
    public static String enumToString(MyEnum value) {
        return value.toString();
    }
}

When the enumToString function is called in Excel with a string argument, Jinx will use the registered argument converter to convert it to a MyEnum and call the enumToString method.

Custom Return Value Converters

In the same way as arguments can be automatically converted using @ExcelArgumentConverter, return types can also be converted to native Excel types using @ExcelReturnConverter.

When a return type has no direct mapping to an Excel type, by default it will be added to the object cache and a handle to the cached object is returned (see above). This is not always desirable as for simple types like enums returning an object handle is confusing to the user.

Return value converters are methods annotated with the @ExcelReturnConverter annotation. When a function returns a value whose type has a return converter registered, that return converter is called to convert the value before returning it to Excel.

Return converters are most useful when used in conjunction with argument converters. To complete the example above the return converter for the enum would be written as:

import com.exceljava.jinx.ExcelReturnConverter;

class MyEnumConverter {
    @ExcelReturnConverter
    public static String stringFromEnum(MyEnum value) {
        switch (value) {
            case X:
                return "X";
            case Y:
                return "Y";
            // etc...    
        }
    }
}

This class has to be added to the list of classes for Jinx to load, and once it is methods that return MyEnum will use the conversion method without any additional code.

import com.exceljava.jinx.ExcelFunction;

class MyEnumFunction {
    @ExcelFunction
    public static MyEnum enumX() {
        return MyEnum.X;  // automatically converted to String before returned to Excel
    }
}

Generic Type Converters

New in Jinx 2.1

Both @ExcelArgumentConverter and @ExcelReturnConverter support using generic methods as type converters. When converting between types Jinx will select a converter that can be satisfied by the type being converted from or to.

This can be especially helpful when writing your own type converters for collections. Rather than having to specify a converter for each parameterized type of the collection you can use a generic method instead.

The following shows a custom type converter that will convert between numeric arrays and the List type.

@ExcelArgumentConverter
public static <T extends Number> List<T> numberArrayToList(T[] array) {
    return Arrays.asList(array);
}

@ExcelReturnConverter
public static <T extends Number> Number[] numberListToArray(List<T> list) {
    Number[] result = new Number[list.size()];
    return list.toArray(result);
}

// The argument will be converted from an array to a
// List<Integer> via 'numberArrayToList' automatically
@ExcelFunction
public static int sumOfList(List<Integer> list) {
    int sum = 0;
    for (int i: list) {
        sum += i;
    }
    return sum;
}

You should avoid making your return converters apply to broadly as there may be some times where it’s more appropriate to use a cached object rather than unpacking the list to an Excel range.