robin
robin

Reputation: 1925

How to force spring org.springframework.format.annotation.DateTimeFormat to custom DateFormatter

I have a scenario where I have different types of dates coming, in that case the existing spring conversion is failing as vales coming are in different formats.

Is there a way I can make Spring use my custom DateFormatter ?

Upvotes: 0

Views: 991

Answers (1)

Denis Zavedeev
Denis Zavedeev

Reputation: 8307

Is there a way I can make Spring use my custom DateFormatter ?

Yes but as your use case is specific I believe it is better to use a custom annotation to make everything explicit.

These interfaces can be used to accomplish this task:

These classes source code can be used as a reference:

You could do something like this:

The UnstableDateFormats annotation

@Retention(RUNTIME)
public @interface UnstableDateFormats {
  String[] formatsToTry();
}

The Formatter implementation

public class UnstableDateFormatter implements Formatter<LocalDate> {
  private final List<String> formatsToTry;

  public UnstableDateFormatter(List<String> formatsToTry) {
    this.formatsToTry = formatsToTry;
  }

  @Override
  public LocalDate parse(String text, Locale locale) throws ParseException {
    for (String format : formatsToTry) {
      try {
        return LocalDate.parse(text, DateTimeFormatter.ofPattern(format));
      } catch (DateTimeParseException ignore) {
        // or log the exception
      }
    }
    throw new IllegalArgumentException("Unable to parse \"" + text
        + "\" as LocalDate using formats = " + String.join(", ", formatsToTry));
  }

  @Override
  public String print(LocalDate object, Locale locale) {
    // Implement this method thoroughly
    // If you're accepting dates in different formats which one should be used to print the value?
    return object.toString();
  }
}

The AnnotationFormatterFactory implementation

public class UnstableDateFormatAnnotationFormatterFactory implements AnnotationFormatterFactory<UnstableDateFormats> {
  @Override
  public Set<Class<?>> getFieldTypes() {
    return Collections.singleton(LocalDate.class);
  }

  @Override
  public Printer<?> getPrinter(UnstableDateFormats annotation, Class<?> fieldType) {
    return new UnstableDateFormatter(Arrays.asList(annotation.formatsToTry()));
  }

  @Override
  public Parser<?> getParser(UnstableDateFormats annotation, Class<?> fieldType) {
    return new UnstableDateFormatter(Arrays.asList(annotation.formatsToTry()));
  }
}

Don't forget to register the AnnotationFormatterFactory implementation:

If you are using spring mvc you can do it in the web configuration (see Type Conversion):

public class MvcConfig implements WebMvcConfigurer {
  @Override
  public void addFormatters(FormatterRegistry registry) {
    registry.addFormatterForFieldAnnotation(new UnstableDateFormatAnnotationFormatterFactory());
  }
}

See also:

You may also want to consider:

Upvotes: 2

Related Questions