@Inject, @Named, @Resource, @Priority

These are the standard Java (JSR-330 and JSR-250, now Jakarta) injection names, for code that prefers them to the Spring ones.

Why

Code ported from Java often uses @Inject and @Named instead of @Autowired and @Component. These names let it read the same in Dart. Each one maps to a Spring-style feature:

Name Same as Where it lives
@Inject() @Autowired() spring_core_dart.dart
@Named('x') on a class @Component('x') spring_core_dart.dart
@Named('x') on an injection point @Qualifier('x') spring_core_dart.dart
@Resource(name: 'x') injection by bean name jakarta.dart
@Priority(n) ranking among beans of one type jakarta.dart
Provider<T> ObjectProvider<T> (subset) jakarta.dart

Provider, Resource and Priority are in package:spring_core_dart/jakarta.dart, which spring_core_dart.dart does not export. Their names clash: Provider with package:provider, Resource with this package's own Resource type. Import the library with a prefix where a name clashes.

If you write new code and do not need to match Java sources, the Spring names are enough.

@Inject

Behaves like @Autowired() (with required: true): on a field, a setter, a method or a constructor.

@Named

On a class it declares a bean, like @Component. On an injection point it selects a bean, like @Qualifier.

@Resource

Injects a field or setter by bean name, where @Autowired chooses by type. It helps when many beans share a type.

@Priority

Ranks a bean among others of the same type, on a bean class or a @Bean method. It does two jobs:

Provider

A Provider<T> injection point gets the same handle as ObjectProvider<T>. Each get() looks the bean up again. Use it for a bean needed fresh on every use, or to break a cycle.

Example

import 'package:spring_core_dart/spring_core_dart.dart';
import 'package:spring_core_dart/jakarta.dart' as jakarta;

abstract interface class Store {
  void put(String key, String value);
}

// Two stores; the fast one ranks first.
@Named('fastStore')
@jakarta.Priority(1)
class FastStore implements Store {
  @override
  void put(String key, String value) {}
}

@Named('archiveStore')
@jakarta.Priority(5)
class ArchiveStore implements Store {
  @override
  void put(String key, String value) {}
}

@Named()
class Clock {
  DateTime now() => DateTime.now();
}

@Named()
class Reports {
  // Constructor parameter selected by name.
  Reports(@Named('archiveStore') this.archive, this.clock);

  final Store archive;

  // Looked up on every get().
  final jakarta.Provider<Clock> clock;

  // Store wins by @Priority: the FastStore.
  @Inject()
  late final Store store;

  // Exactly the bean named 'archiveStore'.
  @jakarta.Resource(name: 'archiveStore')
  late final Store backup;

  String stamp() => clock.get().now().toIso8601String();
}

Parameters

Annotation Name Type Default Meaning
Inject none
Named name (positional) String? null The bean name (on a class) or the qualifier (on an injection point).
Resource name String? null The bean name. null uses the field or setter name, with a fallback to injection by type.
Priority value (positional) int required The priority. Lower values win and sort first.

Provider<T> has one method: T get(). It throws NoSuchBeanDefinitionException when no bean matches and NoUniqueBeanDefinitionException when several match and none wins.

In Spring (Java)

@Named("fastStore")
@Priority(1)
class FastStore implements Store { ... }

@Named
class Reports {
  @Inject
  Reports(@Named("archiveStore") Store archive, Provider<Clock> clock) { ... }

  @Inject Store store;
  @Resource(name = "archiveStore") Store backup;
}

Differences that matter:

See also