or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

annotation-config.mdaot.mdcaching.mdcontext-lifecycle.mdevents.mdformatting.mdi18n.mdindex.mdjmx.mdresilience.mdscheduling.mdstereotypes.mdvalidation.md
tile.json

formatting.mddocs/

Formatting and Type Conversion

@DateTimeFormat

public class EventForm {

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate eventDate;

    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
    private LocalDateTime createdAt;

    @DateTimeFormat(pattern = "HH:mm:ss")
    private LocalTime startTime;

    @DateTimeFormat(style = "MM")  // Medium date, medium time
    private LocalDateTime timestamp;

    @DateTimeFormat(pattern = "yyyy-MM-dd",
                   fallbackPatterns = {"dd/MM/yyyy", "MM-dd-yyyy"})
    private LocalDate flexibleDate;
}

@NumberFormat

public class ProductForm {

    @NumberFormat(style = NumberFormat.Style.CURRENCY)
    private BigDecimal price;

    @NumberFormat(style = NumberFormat.Style.PERCENT)
    private Double discountRate;

    @NumberFormat(pattern = "#,###.##")
    private Double quantity;

    @NumberFormat(pattern = "$#,##0.00;-$#,##0.00")
    private BigDecimal profit;
}

@DurationFormat (Spring 7.0+)

public class TaskConfig {

    @DurationFormat(style = DurationFormat.Style.ISO8601)
    private Duration timeout;  // PT1H30M

    @DurationFormat(style = DurationFormat.Style.SIMPLE)
    private Duration cacheRefresh;  // 1h 30m

    @DurationFormat(style = DurationFormat.Style.COMPOSITE)
    private Duration maxExecution;  // 1h12m27s
}

Custom Formatter

public class PhoneNumberFormatter implements Formatter<PhoneNumber> {

    @Override
    public PhoneNumber parse(String text, Locale locale) throws ParseException {
        String digits = text.replaceAll("[^0-9]", "");
        if (digits.length() != 10) {
            throw new ParseException("Invalid phone number", 0);
        }
        return new PhoneNumber(digits);
    }

    @Override
    public String print(PhoneNumber number, Locale locale) {
        String digits = number.getDigits();
        return String.format("(%s) %s-%s",
            digits.substring(0, 3),
            digits.substring(3, 6),
            digits.substring(6, 10));
    }
}

FormatterRegistrar

@Configuration
public class FormattingConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        // Register formatter
        registry.addFormatter(new PhoneNumberFormatter());

        // Register by field type
        registry.addFormatterForFieldType(
            Currency.class,
            new CurrencyFormatter()
        );

        // Register annotation factory
        registry.addFormatterForFieldAnnotation(
            new DateTimeFormatAnnotationFormatterFactory()
        );

        // Date/time registrar
        DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
        registrar.setUseIsoFormat(true);
        registrar.registerFormatters(registry);
    }
}

AnnotationFormatterFactory

public class CurrencyFormatterFactory
        implements AnnotationFormatterFactory<CurrencyFormat> {

    @Override
    public Set<Class<?>> getFieldTypes() {
        return Set.of(BigDecimal.class, Double.class);
    }

    @Override
    public Printer<?> getPrinter(CurrencyFormat annotation, Class<?> fieldType) {
        return new CurrencyPrinter(annotation.currencyCode());
    }

    @Override
    public Parser<?> getParser(CurrencyFormat annotation, Class<?> fieldType) {
        return new CurrencyParser(annotation.currencyCode());
    }
}

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrencyFormat {
    String currencyCode() default "USD";
}

Number Formatters

// Number style
NumberStyleFormatter formatter = new NumberStyleFormatter("#,###.00");
formatter.setLenient(true);

// Currency style
CurrencyStyleFormatter currencyFormatter = new CurrencyStyleFormatter();
currencyFormatter.setFractionDigits(2);
currencyFormatter.setRoundingMode(RoundingMode.HALF_UP);
currencyFormatter.setCurrency(Currency.getInstance("USD"));

// Percent style
PercentStyleFormatter percentFormatter = new PercentStyleFormatter();

JSR-354 Money Support

// Requires JSR-354 implementation (e.g., Moneta)
<dependency>
    <groupId>org.javamoney</groupId>
    <artifactId>moneta</artifactId>
    <version>1.4.2</version>
</dependency>

// Formatters
MonetaryAmountFormatter amountFormatter = new MonetaryAmountFormatter();
CurrencyUnitFormatter currencyFormatter = new CurrencyUnitFormatter();

// Usage
MonetaryAmount amount = Money.of(99.99, "USD");
String formatted = amountFormatter.print(amount, Locale.US);  // "$99.99"