spring_boot_dart 0.2.1
spring_boot_dart: ^0.2.1 copied to clipboard
Spring Boot for Dart and Flutter: @SpringBootApplication, SpringApplication.run, @ConfigurationProperties, auto-configuration and starters, runners, failure reports.
0.2.1 #
--dart-definevalues as properties:SpringApplication(dartDefines: ...)(filled by the generator) adds them right below the command-line arguments with relaxed names like environment variables (API_URLanswersapi.url;SPRING_PROFILES_ACTIVEactivates profiles)run/runAsync(additionalProfiles: [...]): profiles for one launch after the application's ownadditionalProfiles, kept byreload/reloadAsync(Flutter's platform profiles)
0.2.0 #
- breaking:
@ConditionalOnBean,@ConditionalOnMissingBeanand@ConditionalOnSingleCandidateareregisterBean-phaseConfigurationConditions, like Boot'sOnBeanCondition: they are decided when the configuration class is read, class by class (application classes before auto-configurations; a scanned@Componentor an@Imported class counts as a class too, at its place in that order), so the beans of an@ImportedBeanRegistrar/ImportBeanDefinitionRegistrarand of earlier classes make an auto-configuration, or a later@ConditionalOnMissingBean@Bean, back off (there were twoCacheManagers,ObjectMappers orHttpTransports), and a@Component@ConditionalOnMissingBean/@ConditionalOnBeansees the beans of earlier classes'@Beanmethods and registrars; a class-level bean condition decides the class, its@Beanmethods and its imports once (a skipped class runs no registrar; a@ConditionalOnMissingBean(X)class importing the class that definesXstays, like Boot'sPooledDataSourceConfiguration) and no longer stops the class's@PropertySources; the built-in auto-configuration beans are@Beanmethods (factoryMethodName); excluding one class of an auto-configuration module keeps the@Imports of its other classes (they were dropped) and drops the excluded class's own ApplicationRunner/CommandLineRunnerandExitCodeGeneratorbeans registered withregisterSingleton(no bean definition) are called and asked for their code; they failed with aNoSuchBeanDefinitionException- the lines logged before
logging.level.*applies (ApplicationStartingEvent/ApplicationEnvironmentPreparedEventlisteners, config data, the banner in log mode) are held and emitted at the final levels (were dropped below WARN); the levels apply right afterApplicationEnvironmentPreparedEvent, before the banner, like Boot'sLoggingApplicationListener @ConfigurationProperties(ignoreInvalidFields: true): a comma list with an invalid element keeps the default, like Boot (was the valid elements)- validation auto-configuration:
defaultValidatorbacks off only for aBeanValidatorbean (a plain formValidatorno longer removes it) and method validation uses the uniqueBeanValidator(two plainValidatorbeans no longer fail the start) - breaking:
@ConditionalOnBean/@ConditionalOnMissingBeanwithout arguments check the@Beanmethod's return type;.where(types:, names:, annotations:, search:)(andignored:for the missing one),.named(..., search:); newSearchStrategy; the auto-configuredmessageSourcelooks at the current context only (SearchStrategy.current), like Boot @ConditionalOnCloudPlatform(CloudPlatform.x)@ConfigurationProperties(ignoreInvalidFields:, ignoreUnknownFields:)- binding: a nullable nested value object none of whose own keys is set stays
null(was "no value bound" for its required parameters) - breaking:
ApplicationContextInitializeris a class (initialize(context), orApplicationContextInitializer.of(...)), sorted byOrdered;LazyInitializationExcludeFilterbeans;SPRING_APPLICATION_JSON/spring.application.json(SpringApplicationJsonEnvironmentPostProcessor) spring.messages.encoding,always-use-message-format,common-messages;runAsyncprints abanner.txtthat is readable asynchronously only (a Flutter asset)- an exit code generator that throws, followed by one returning 0, gives 1 (was 0);
ApplicationFailedEventreaches the listeners added withcontext.addApplicationListenerwhen the context did not start selectAutoConfigurationsis exported (Boot's exclusions andAutoConfigurationSorterorder, used byApplicationContextRunner).- A failed start is logged like Spring Boot: the failure analysis at error level under
spring_boot_dart.diagnostics.LoggingFailureAnalysisReporter, any other failure asApplication run failedwith the error and stack trace (refresh failures without an analysis were not reported at all). Breaking:SpringApplication(out:)is optional and, when given, receives the reports instead of the log. DeferredLogs: what is logged while an application starts is handed to the logging system (beanspringBootDeferredLogs), which replays it.logging.level.<logger>: false(YAML'soff) is OFF, like Boot's lenient enum conversion.- Jackson:
spring.jackson.deserialization.fail-on-null-for-primitives(true, Jackson 3's default) - Jackson:
spring.jackson.datatype.datetime.write-durations-as-timestamps/write-date-timestamps-as-nanoseconds/read-date-timestamps-as-nanoseconds,deserialization.accept-float-as-int,mapper.default-view-inclusion;default-property-inclusionacceptsnon_absentandnon_default; breaking: date timestamps are seconds with the fraction (Jackson 3), durations stay ISO-8601 unlesswrite-durations-as-timestamps @ConditionalOnBean/@ConditionalOnMissingBeandocumented and tested to ignoreautowireCandidate: falseanddefaultCandidate: falsebeans, like Boot 3.4+- the shutdown hook (
registerShutdownHook: true/spring.main.register-shutdown-hook) delegates to the core'scontext.registerShutdownHook(); behaviour unchanged (off by default) - breaking: the auto-configured mapper bean is named
jacksonJsonMapper(Boot 4's name) instead ofobjectMapper - Jackson:
spring.jackson.datatype.datetime.write-dates-as-timestamps(Boot 4; wins overspring.jackson.serialization.write-dates-as-timestamps); any other unsupportedspring.jackson.*key is logged as a warning naming it; a namedspring.jackson.time-zonefails with a message that onlyUTCand fixed offsets are supported ${random.*}placeholders:SpringApplicationadds aRandomValuePropertySourceafter the system environment, like Boot- binding: environment variables bind nested objects under dashed names (
APP_MAIN_SERVER_HOST→app.main-server.host, Boot's legacy ancestor check);@Name,@DurationUnit(ChronoUnit.x),@DataSizeUnit(DataUnit.x);BindHandler(Binder.bind(handler:));BindResult.map/ifBound/orElseGet/orElseThrow @ConfigurationPropertieson@Beanmethods binds the returned object (@Validated()on the method validates it);ConfigurationPropertiesBinder(beanFactory:)- validation of bound objects like Boot: the
configurationPropertiesValidatorbean (ConfigurationPropertiesBinder.validatorBeanName) and self-validating properties classes (a properties class that is aValidator) EnvironmentPostProcessor(SpringApplication(environmentPostProcessors:)), run before or after config data by order (EnvironmentPostProcessor.configDataOrder)- conditions:
ConditionalOnProperty(prefix:)andConditionalOnProperty.names([...]),@ConditionalOnBooleanProperty,@ConditionalOnSingleCandidate,@ConditionalOnExpression,@ConditionalOnResource,ConditionalOnBean.named;ConditionEvaluationReport, logged at INFO for--debug/debug=true(with a hint after a failed start otherwise) JsonMapperBuilderCustomizerbeans for the auto-configured mapper: they receive the coreJsonMapperBuilder(jsonMapperBuilderFromProperties)- banner:
Banner,SpringBootBanner,ResourceBanner,BannerMode(SpringApplication(banner:, bannerMode:),spring.main.banner-mode,classpath:banner.txt/spring.banner.location); printed by default like Boot - failure analysis for
BeanDefinitionOverrideException, missing config data (ConfigDataResourceNotFoundException,ConfigDataLocationNotFoundException) and invalid property names - breaking:
SpringApplication.exitand failed runs take the first non-zero code of the generators sorted by order (Boot 3+), not the highest - breaking: an invalid
logging.level.*value fails the start (Boot's binding toLogLevel);logging.group.<name>andspring.messages.basenameaccept YAML lists ApplicationArgumentsparses likeSimpleCommandLinePropertySource: a lone--ends the options,--=xis an errorspring.messages.cache-durationkeeps sub-second values (500ms);spring.messages.use-code-as-default-message/fallback-to-system-localeare read case-insensitively
0.1.7 #
SpringApplication.runAsync/reloadAsyncrefresh with the context'srefreshAsync()(asynchronous@PostConstruct/ init methods are awaited before the runners) and close withcloseAsync();runfails for an asynchronous init callback- breaking:
SpringApplication.runandApplicationFailedEvent.exceptionreport a missing or ambiguous dependency as anUnsatisfiedDependencyException(itscauseis theNoSuchBeanDefinitionException/NoUniqueBeanDefinitionException); the failure analysis is unchanged SpringApplication(defaultProperties:)/setDefaultProperties(Boot'ssetDefaultProperties): thedefaultPropertiessource below every other one, config files included;additionalProfiles:(Boot'ssetAdditionalProfiles)@AutoConfigurationisproxyBeanMethods: false, like Boot's: its@Beanmethods are called as written@ConfigurationPropertiesbind collections like Boot'sBinder: indexed lists (app.hosts[0], YAML lists,APP_HOSTS_0_) next to comma lists, maps (app.headers.X-Shop,app.headers[x.y]; keys keep their form), lists and maps of nested objects (app.servers[0].name,app.backends.eu.url); a list from a higher-precedence source replaces the whole list, map entries merge per key; elements are converted through the conversion service and failures name the property (app.ports[0]: failed to convert to int (was "x")).Binder/BindResultbind outside of a properties class- constructor binding: a
@ConfigurationPropertiesclass whose only constructor has parameters is created through it, parameters bound from properties, with@DefaultValue(Boot's), Dart defaults,nullfor nullable parameters, nested constructor-bound classes and collections; a missing required value fails the start naming the property (ConstructorBound, used by the generated code) - application events in Boot's order:
ApplicationStartingEvent,ApplicationEnvironmentPreparedEvent,ApplicationContextInitializedEvent,ApplicationPreparedEvent,ApplicationStartedEvent,ApplicationReadyEvent,ApplicationFailedEvent; listeners onSpringApplication(listeners:)/addListeners/addListener, the later events also reach@EventListenerbeans - breaking: a
@ConfigurationPropertiesprefix must be in canonical form (my-app, notmyApp), as in Boot;ConfigurationPropertiesBindException.beanNameis nullable (nullforBinder.bind);ConfigurationPropertiesBinder.kebabCaseis removed - breaking:
SpringApplicationloadsapplication.yml/application.yamltoo, searches Boot's two location groups (./application.propertiesbeats a packagedapplication-prod.properties,./config/*/is searched) and attaches relaxed names (app.read-timeoutfindsapp.readTimeout,APP_READTIMEOUT), seespring_core_dart logging.level.ROOT(any case) sets the root level instead of a logger named "ROOT"- breaking: the auto-configured message source is a
ReloadableResourceBundleMessageSource;spring.messages.fallback-to-system-locale(defaulttrue) andspring.messages.cache-duration(seconds without a unit) are supported - the context id is
spring.application.name(orapplication), like Spring Boot'sContextIdApplicationContextInitializer - breaking:
@ConfigurationPropertiesare validated only with@Validated()on the class, like Spring Boot;ConfigurationProperties(validate:)is removed ValidationAutoConfiguration: adefaultValidator(BeanValidator, backs off for an applicationValidator) and amethodValidationPostProcessor(not applied to@ConfigurationPropertiesclasses)FailureAnalyzer(Boot's interface), registered onSpringApplication(failureAnalyzers:)or as beans; consulted before the built-in analysis- breaking: startup info is logged through
SpringLog(spring_boot_dart.SpringApplication) at INFO like Boot's:Starting <app> using Dart <version> with PID <pid>, the active / default profiles,Started <app> in <x> seconds(was a printedStarted <app> in <n> ms (profiles: ...)line);outonly gets failure reports spring.main.lazy-initialization(LazyInitializationBeanFactoryPostProcessor) andspring.main.allow-bean-definition-overriding(defaultfalse)- dotted
spring.messages.basenamevalues are paths (config.i18n.messages→config/i18n/messages), like Boot JacksonAutoConfigurationregistersJsonSerializer/JsonDeserializerbeans (Boot's@JsonComponent) and readsspring.jackson.time-zone(UTCor a fixed offset such as+02:00)- breaking: the JSON property order is Jackson 3's / Boot 4's (sorted by JSON name, constructor parameters first);
spring.jackson.mapper.sort-properties-alphabetically=falserestores declaration order - breaking: auto-configurations are registered in Boot's
AutoConfigurationSorterorder (module name,AutoConfigurationModule.order,before/after; a cycle fails the start), not in the order they are listed AutoConfigurationModule(before:, after:);SpringApplication(autoConfigurationMetadata:)carries them from the generated code- auto-configuration exclusion:
@SpringBootApplication(exclude:, excludeName:),SpringApplication(exclude:, excludeName:)andspring.autoconfigure.exclude(types, class names or module names), applied before conditions run; excluding a type that is no auto-configuration fails the start SpringApplication.exit(context, [generators])withExitCodeGeneratorbeans (highest non-zero code wins),ExitCodeEvent,ExitCodeExceptionMapperbeans andSpringApplication.exitCodeOf(error)for failed runs- shutdown hook: with
spring.main.register-shutdown-hook=trueorSpringApplication(registerShutdownHook: true)the context is closed on SIGINT / SIGTERM and the process exits with130/143; off by default, unlike Boot, because the signal listener keeps a Dart program alive until the context closes; nothing on the web
0.1.6 #
- update road map
- ci: release with a button on main, skip new packages when publishing; shorter pubspec descriptions
0.1.5 #
- Runners as in Spring Boot:
ApplicationRunner/CommandLineRunnermay return aFuture; runners run one after another (a runner'sFuturecompletes before the next starts),runAsync/runApplicationAsynccomplete after the last one, a failing runner is reported (Application run failed) and closes the context. The startup line now comes before the runners, as in Spring Boot.
0.1.4 #
- feat: ObjectMapper in core — JSON on generated metadata (@Introspected, @JsonProperty/@JsonIgnore/@JsonInclude/@JsonCreator/@JsonValue), spring.jackson.* in Boot
0.1.3 #
- add scheduling + cache starters
- fix extension add aop docs
0.1.2 #
- ci: release only from the release branch; fix version-dependent test; Node 24 actions
- fix tests
0.1.1 #
- Hot reload:
SpringApplication(fingerprint:),reload/reloadAsynckeep the running context when the generated code is unchanged and restart it with the same arguments otherwise;runners: falseskipsApplicationRunner/CommandLineRunnerbeans after such a restart. - Example on pub.dev (
example/) and a description within 180 characters. - Failure reports point to
lib/resources/application.propertiesand suggest@Lazy()for dependency cycles.
0.1.0 #
Initial version.
@SpringBootApplication(withspring_core_dart_generator: package-wide scan and a generatedrunApplication),SpringApplication.run/runAsync.@ConfigurationPropertiesbinding (kebab-case, camelCase and environment variable names) with validation.@AutoConfiguration,@ConditionalOnProperty,@ConditionalOnBean,@ConditionalOnMissingBean.- Starters:
@AutoConfigurationModuleinlib/spring_auto_configuration.dart, discovered by the generator in all dependencies;MessageSourceAutoConfiguration;ConditionalOnMissingBean.named. AutoConfigurationModule(requires:)with a build-time compatibility check againstspringBootVersion.- Generated
runApplicationAsyncfor asynchronous config (Flutter assets). ApplicationArguments,ApplicationRunner,CommandLineRunner(both kinds sorted together by order, a bean implementing both called as both), startup line and failure analysis reports.logging.level.root,logging.level.<logger>,logging.group.*andLOGGING_LEVEL_*variables applied toSpringLog(SpringApplication.applyLoggingLevels).SpringApplication(initializers:)(ApplicationContextInitializer) andrun(args, properties:)with the highest precedence.