Skip to main content

spring_core_dart_generator 0.6.0 copy "spring_core_dart_generator: ^0.6.0" to clipboard
spring_core_dart_generator: ^0.6.0 copied to clipboard

Code generator for spring_core_dart: turns @Component, @Bean, @Value, @Aspect and other annotations into bean definitions, metadata and AOP proxies.

example/README.md

spring_core_dart_generator: examples #

What it does: it reads the annotations of spring_core_dart (@Service, @Value, @Bean, @Aspect...) and writes plain Dart code that creates and connects your objects. Dart has no runtime reflection in Flutter, AOT executables or on the web, so this step happens at build time. It is required: without it the annotations do nothing.

This page walks through one small app: the setup, the command to run, the file the generator writes, and the errors it reports.

Setup #

dependencies:
  spring_core_dart: ^0.6.0

dev_dependencies:
  build_runner: ^2.17.0
  spring_core_dart_generator: ^0.6.0

Mark the scan root. Every class in this file's directory and below (here lib/src/) is scanned:

// lib/src/app.dart
import 'package:spring_core_dart/spring_core_dart.dart';
import 'app.spring.dart'; // created by the generator

@ComponentScan()
final BeanModule appBeans = $appBeans;

A bean to scan:

// lib/src/greeter.dart
import 'package:spring_core_dart/spring_core_dart.dart';

@Service()
class Greeter {
  Greeter(@Value(r'${greeting.suffix:!}') this.suffix);
  final String suffix;

  String greet(String name) => 'Hello, $name$suffix';
}

And main, which starts the container with the generated module:

// bin/main.dart
import 'package:spring_core_dart/spring_core_dart.dart';
import 'package:my_app/src/app.dart';
import 'package:my_app/src/greeter.dart';

const log = SpringLog('app'); // a logger by name, for code outside beans

void main() {
  final context = ApplicationContext.run([appBeans]);
  log.info(context.getBean<Greeter>().greet('Ada')); // Hello, Ada!
  context.close();
}

With spring_boot_dart you skip app.dart and write @SpringBootApplication() on main instead; the generator then scans lib/ and the directory of main.

Run it #

dart run build_runner build   # once
dart run build_runner watch   # regenerate on every save
dart run bin/main.dart

The generator writes app.spring.dart next to app.dart. Commit the generated files: then the app builds without running the generator first (in CI, for other developers).

What it writes #

For Greeter above it generates (simplified; the real file uses import prefixes such as _i1.):

BeanModule get $appBeans => BeanModule(r'appBeans', [
  BeanDefinition<Greeter>(
    name: r'greeter',
    types: const [Greeter],
    dependencies: const [Dependency.value(r'${greeting.suffix:!}')],
    create: (r) => Greeter(r.value<String>(r'${greeting.suffix:!}')),
  ),
]);

create is a plain constructor call: fast, available in AOT, Flutter and on the web, and unaffected by minification. The container calls it with a resolver r that hands out the dependencies and settings.

Mistakes are build errors, not crashes #

The generator checks what it can before the app ever runs:

@Service()
class Report {
  @Autowired()
  final Clock clock;
  // ✗ Injected field clock must be settable: declare it `late final` or non-final.
}

@Service()
class Inbox {
  @Autowired()
  late final Mailer _mailer;
  // ✗ Injected field _mailer must be public: the generated code is another
  //   library and cannot reach a private member; ...
}

@Service()
class Shop {
  Shop(@Lazy() this.repo);
  final Repository? repo;
  // ✗ @Lazy on repo: a lazy dependency cannot be nullable; use
  //   ObjectProvider<Repository> for an optional lazy bean.
}

Missing or ambiguous beans and dependency cycles depend on the whole application, so they are reported when the context starts, before any of your objects is created.

Options #

# build.yaml of your package
targets:
  $default:
    builders:
      spring_core_dart_generator:spring_core_dart:
        options:
          aop_proxies: all   # all (default) | interfaces | none

aop_proxies controls the proxy classes that @Aspect advice needs. interfaces generates proxies only through a bean's abstract supertypes (less code; a bean without one cannot be advised), none generates no proxies, so AOP cannot advise the beans. The second option, aop_prune, is described in the package README.

Resources #

Files in lib/resources/ are embedded into the generated code, so classpath:application.properties and @Value('classpath:logo.png') work everywhere without declaring Flutter assets.

More #

0
likes
160
points
772
downloads

Documentation

API reference

Publisher

verified publisherfarum-azula.org

Weekly Downloads

Code generator for spring_core_dart: turns @Component, @Bean, @Value, @Aspect and other annotations into bean definitions, metadata and AOP proxies.

Repository (GitHub)
View/report issues

Topics

#dependency-injection #code-generation #build-runner #aop #spring

License

Apache-2.0 (license)

Dependencies

analyzer, build, code_builder, dart_style, glob, path, pub_semver, source_gen, spring_core_dart, yaml

More

Packages that depend on spring_core_dart_generator