Brad Mace
Brad Mace

Reputation: 27886

Custom formatters with generics in Play 2.0

I want to register a custom formatter for handling Set<Integer>.

The obvious way:

Formatters.register(Set<Integer>.class, new AnnotationIntegerSetFormatter());

results in "Illegal start of expression". What's the right way to do this, or is it not possible?

Upvotes: 3

Views: 803

Answers (2)

Brad Mace
Brad Mace

Reputation: 27886

Ended up using Formatters.register(Set.class, new AnnotationIntegerSetFormatter());; parse can still return Set<Integer> and in print just cast the Set to Set<Integer>:

public class AnnotationIntegerSetFormatter extends Formatters.AnnotationFormatter<IntegerSet,Set> {
    @Override
    public Set<Integer> parse(IntegerSet annotation, String text, Locale locale) {
        Set<Integer> set = new TreeSet<Integer>();
        for (String part : text.split(","))
            set.add(Integer.parseInt(part));

        return set;
    }

    @Override
    public String print(IntegerSet annotation, Set value, Locale locale) {
        List<Integer> sorted = new ArrayList<Integer>();
        sorted.addAll((Set<Integer>) value);
        Collections.sort(sorted);

        return join(",", sorted.toArray());
    }

    private static String join(String separator, Object... values) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < values.length; i++) {
            if (values[i] == null)
                continue;

            if (sb.length() > 0)
                sb.append(separator);

            sb.append(values[i].toString());
        }

        return sb.toString();
    }

}

and for completeness, the annotation I used:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface IntegerSet {
    int min() default Integer.MIN_VALUE;
    int max() default Integer.MAX_VALUE;
}

Since this is annotation based, it appears you can register multiple formatters for a Collection type and have them distinguished by the annotations.

Upvotes: 2

jon hanson
jon hanson

Reputation: 9408

Set<Integer>.class isn't legal Java, as the generic component of the type is erased at compile-time. I think using Set.class should work, though this will register your handler for all Set<T> types.

Upvotes: 3

Related Questions