ConversionService

ConversionService turns a value into a value of another type, such as the text '10s' from a config file into a Duration.

Why use it

The framework calls a conversion service whenever it fills a typed value: @Value injection, PropertyResolver.getPropertyAs<T> and @ConfigurationProperties binding. DefaultConversionService already knows the usual types, so most applications only receive the results.

Use it yourself in two cases:

You also call convert<T> directly to convert values in your own code.

Built into DefaultConversionService:

Example

import 'package:spring_core_dart/spring_core_dart.dart';

/// An amount of money, written `12.50 EUR` in config files.
class Money {
  const Money(this.amount, this.currency);

  final double amount;
  final String currency;

  static Money parse(String text) {
    final [amount, currency] = text.trim().split(' ');
    return Money(double.parse(amount), currency);
  }
}

enum Level { info, warn, error }

@Configuration()
class ConversionConfig {
  // The context uses this bean to convert @Value arguments, so
  // `@Value(r'${shop.min-order}') Money minOrder` works.
  @Bean()
  ConversionService conversionService() => DefaultConversionService()
    ..addConverter<String, Money>(Money.parse)
    ..addCollectionConverters<Money>() // List<Money> and Set<Money>
    ..addEnum(Level.values); // `warn`, `WARN` and `Warn` all match
}

@Service()
class Checkout {
  Checkout(
    @Value(r'${shop.min-order:10.00 EUR}') this.minOrder,
    @Value(r'${shop.alert-level:warn}') this.alertLevel,
  );

  final Money minOrder;
  final Level alertLevel;
}

Converting in code:

final service = DefaultConversionService();
service.convert<int>('0x1F'); // 31
service.convert<bool>('yes'); // true
service.convert<List<int>>('1, 2, 3'); // [1, 2, 3]
service.convert<int?>(''); // null
service.convert<String>(const Duration(seconds: 10)); // 'PT10S'

Errors:

Members

ConversionService:

Name Returns Meaning
convert<T>(source) T Converts to T; returns the source unchanged when it already is a T.
convertTo(source, targetType) Object? Converts to a target known only as a Type value at run time.
canConvert(source, targetType) bool Whether a converter accepts this value. It does not check that the value parses.
canConvertType<S>(targetType) bool Whether values of type S can be converted, before any value exists.

ConverterRegistry (implemented by GenericConversionService and DefaultConversionService):

Name Meaning
addConverter<S, T>(converter) Adds a function from S to exactly T (it also serves T?). A later registration for the same target wins.
addEnum<E>(values) Makes an enum convertible from and to String, and as List<E> / Set<E>. Names match ignoring case and separators.
addCollectionConverters<E>() Makes List<E> and Set<E> convertible.
addMapConverters<K, V>() Makes Map<K, V> convertible from any map.
removeConvertible<T>() Removes every converter targeting T and T?.

DefaultConversionService.sharedInstance is used by anything that was given no service. Do not add converters to it; create your own instance.

In Spring (Java)

@Bean
ConversionService conversionService() {
  DefaultConversionService service = new DefaultConversionService();
  service.addConverter(String.class, Money.class, Money::parse);
  return service;
}

Integer port = service.convert("8080", Integer.class);

Differences that matter:

See also