Custom Binding Annotation - Tuong-Nguyen/Spring GitHub Wiki

Define a custom formatter to binds fields value using annotation.

Steps to create a new custom formatter annotation:

- Creating Formatter

Implement Formatter<Date> interface with <Date> is data type that is expected to bind.

public class VNDateFormatter implements Formatter<Date> {

    private String pattern;

    public VNDateFormatter(String pattern){
        this.pattern = pattern;
    }
    @Override
    public Date parse(String s, Locale locale) throws ParseException {
        String date = "";
        if (s.length() == 0){
            return null;
        }
        int dayIndex = s.indexOf("ngay");
        int monthIndex = s.indexOf("thang");
        int yearIndex  = s.indexOf("nam");

        if (s.startsWith("ngay")){
            String day = s.substring(dayIndex + 4, monthIndex).trim();
            String month = s.substring(monthIndex + 5, yearIndex).trim();
            String year = s.substring(yearIndex + 3).trim();
            date = day + "/" + month + "/" + year;
        }

        return getDateFormat(locale).parse(date);
    }

    @Override
    public String print(Date date, Locale locale) {
        if (date == null) {
            return "";
        }
        String[] dateArray = getDateFormat(locale).format(date).split("/");
        String printDate = "ngay " + dateArray[0] + " thang " + dateArray[1] + " nam " + dateArray[2];
        return printDate;
    }

    protected DateFormat getDateFormat(Locale locale) {
        DateFormat dateFormat = new SimpleDateFormat(this.pattern, locale);
        dateFormat.setLenient(false);
        return dateFormat;
    }
}

Declare parameters for Formatter as pattern field and override two methods parse and print to custom for binding.

parse method: parse an instance of Date data type from the formatted representation from the client.

print method: print an instance of Date data type for display in the client.

- Creating Annotation

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface VNDateFormat {
    public static final String PATTERN_DEFAULT = "dd/MM/yyyy";
    String pattern() default PATTERN_DEFAULT;
}

The name of interface is name of annotation. In the body of interface, initialize default value for parameters of Formatter i.e VNDateFormatter as shown above.

- Binding annotation to Formatter

Create a class implements AnnotationFormatterFactory<VNDateFormat> interface with data type is annotation that have been created above.

public class VNDateFormatAnnotationFormatterFactory implements AnnotationFormatterFactory<VNDateFormat> {
    @Override
    public Set<Class<?>> getFieldTypes() {
        return new HashSet<>(Arrays.asList(Date.class));
    }

    @Override
    public Printer<?> getPrinter(VNDateFormat vnDateFormat, Class<?> aClass) {
        return getVNDateFormatter(vnDateFormat, aClass);
    }

    @Override
    public Parser<?> getParser(VNDateFormat vnDateFormat, Class<?> aClass) {
        return getVNDateFormatter(vnDateFormat, aClass);
    }

    private Formatter<Date> getVNDateFormatter(VNDateFormat annotation, Class<?> fieldType){
        VNDateFormatter vnDateFormatter = new VNDateFormatter(annotation.pattern());
        return vnDateFormatter;
    }

}

Override:

getFieldTypes method to return the types of fields the annotation may be used on.

getPrinter and getParser method by getting arguments (i.e pattern value) from annotation to pass into Formatter.

- Registering the AnnotationFormatterFactory

In the WebConfig file, override addFormatters method to register AnnotationFormatterFactory above (i.e VNDateFormatAnnotationFormatterFactory)

    @Override
    public void addFormatters(FormatterRegistry registry) {
        VNDateFormatAnnotationFormatterFactory factory = new
                VNDateFormatAnnotationFormatterFactory();

        registry.addFormatterForFieldAnnotation(factory);
    }

- Trigger Formatter

Annotate fields with a new annotation as @VNDateFormat

public class Course {
   private int id;
   private String title;
   private String description;
   @VNDateFormat(pattern = "dd/MM/yyyy")
   private Date startDate;
   @VNDateFormat(pattern = "dd/MM/yyyy")
   private Date endDate;
⚠️ **GitHub.com Fallback** ⚠️