Following example shows how to create a custom annotation for formatting.
Example
This annotation is going to provide custom formatting rules for Locale field.
The annotation
package com.logicbig.example;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface LocaleFormat {
LocaleStyle style() default LocaleStyle.CountryDisplayName;
}
package com.logicbig.example;
public enum LocaleStyle {
CountryDisplayName,
ISO3Country,
ISO3Language;
}
Creating the formatter
Creating the formatter is similar to what we did in a previous tutorial. This formatter has no knowledge of the annotation we created in the last step.
package com.logicbig.example;
import org.springframework.format.Formatter;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Optional;
public class LocaleFormatter implements Formatter<Locale> {
private LocaleStyle localeStyle;
public LocaleStyle getLocaleStyle () {
return localeStyle;
}
public void setLocaleStyle (
LocaleStyle localeStyle) {
this.localeStyle = localeStyle;
}
@Override
public Locale parse (String text, Locale locale) throws ParseException {
Optional<Locale> o = Arrays.stream(Locale.getAvailableLocales()).parallel()
.filter(l -> this.localeByStylePredicate(l, text))
.findAny();
if (o.isPresent()) {
return o.get();
}
return null;
}
@Override
public String print (Locale object, Locale locale) {
switch (localeStyle) {
case CountryDisplayName:
return object.getDisplayCountry();
case ISO3Country:
return object.getISO3Country();
case ISO3Language:
return object.getISO3Language();
}
return object.toString();
}
private boolean localeByStylePredicate (Locale locale, String text) {
try {
switch (localeStyle) {
case CountryDisplayName:
return locale.getDisplayCountry().equalsIgnoreCase(text);
case ISO3Country:
return locale.getISO3Country().equalsIgnoreCase(text);
case ISO3Language:
return locale.getISO3Language().equalsIgnoreCase(text);
}
} catch (MissingResourceException e) {
//ignore;
}
return false;
}
}
Binding annotation with formatter - implementing AnnotationFormatterFactory
Now we are going to bind the annotation and the formatter (created in the last two steps) together by implementing AnnotationFormatterFactory.
Spring on finding the annotation on a field, will look for annotation-formatter mapping, as provided by this factory, and then invoke the corresponding formatter to populate the value to the field.
package com.logicbig.example;
import org.springframework.format.AnnotationFormatterFactory;
import org.springframework.format.Formatter;
import org.springframework.format.Parser;
import org.springframework.format.Printer;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
public class LocaleFormatAnnotationFormatterFactory implements
AnnotationFormatterFactory<LocaleFormat> {
@Override
public Set<Class<?>> getFieldTypes() {
return new HashSet<>(Arrays.asList(Locale.class));
}
@Override
public Printer<?> getPrinter(LocaleFormat annotation, Class<?> fieldType) {
return getLocaleFormatter(annotation, fieldType);
}
@Override
public Parser<?> getParser(LocaleFormat annotation,
Class<?> fieldType) {
return getLocaleFormatter(annotation, fieldType);
}
private Formatter<?> getLocaleFormatter(LocaleFormat annotation, Class<?> fieldType) {
LocaleFormatter lf = new LocaleFormatter();
lf.setLocaleStyle(annotation.style());
return lf;
}
}
Creating the client bean
Now we are going to use our custom annotation, on an example bean.
package com.logicbig.example;
import java.util.Locale;
public class MyBean {
@LocaleFormat(style = LocaleStyle.ISO3Country)
private Locale myLocale;
public Locale getMyLocale() {
return myLocale;
}
public void setMyLocale(Locale myLocale) {
this.myLocale = myLocale;
}
@Override
public String toString() {
return "MyBean{" +
"myLocale=" + myLocale +
'}';
}
}
Registering the factory to DataService and Using DataBinder
package com.logicbig.example;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.validation.BindingResult;
import org.springframework.validation.DataBinder;
import java.text.DateFormat;
import java.util.Locale;
public class CustomFormatAnnotationExample {
public static void main(String[] args) {
DefaultFormattingConversionService service =
new DefaultFormattingConversionService();
service.addFormatterForFieldAnnotation(
new LocaleFormatAnnotationFormatterFactory());
MyBean bean = new MyBean();
DataBinder dataBinder = new DataBinder(bean);
dataBinder.setConversionService(service);
MutablePropertyValues mpv = new MutablePropertyValues();
mpv.add("myLocale", "CYP");
dataBinder.bind(mpv);
Object target = dataBinder.getTarget();
System.out.println(target);
BindingResult bindingResult = dataBinder.getBindingResult();
System.out.println(bindingResult);
System.out.println(bean.getMyLocale().getDisplayName());
}
}
OutputMyBean{myLocale=el_CY} org.springframework.validation.BeanPropertyBindingResult: 0 errors Greek (Cyprus)
Example ProjectDependencies and Technologies Used: - spring-context 6.1.2 (Spring Context)
Version Compatibility: 3.2.3.RELEASE - 6.1.2 Version compatibilities of spring-context with this example: Versions in green have been tested.
- JDK 17
- Maven 3.8.1
|