
# @Value

`@Value` injects a value from the configuration, or the result of an expression, into a constructor parameter or field of a bean.

## Why use it

A bean often needs one or two settings: a port, a URL, a timeout, a feature switch. You do not want them hard-coded, and you do not want to parse config files yourself. `@Value` reads the setting from the environment and converts it to the type of the parameter.

- `${key}` is replaced by the property `key`. `${key:default}` uses `default` when the property is not set.
- `#{...}` is a SpEL expression. It can do arithmetic and read other beans.
- The result is converted to the target type: `int`, `bool`, `Duration`, `List<String>`, `Resource`, and so on.

Use it for a few independent settings. When a feature has several related settings under one prefix, a [`@ConfigurationProperties`](configuration-properties.md) class is clearer. When the key is only known at run time, read the [`Environment`](environment.md) instead.

## Example

```properties
# lib/resources/application.properties
shop.name=NEON Books
shop.delivery-time=2d
shop.tags=books,comics,games
shop.max-basket-size=20
```

```dart
import 'package:spring_core_dart/spring_core_dart.dart';

@Service()
class Shop {
  Shop(
    // Raw strings (r'...'), so Dart does not read `$` as interpolation.
    @Value(r'${shop.name}') this.name,
    // `2d` in the file becomes Duration(days: 2).
    @Value(r'${shop.delivery-time}') this.deliveryTime,
    // 8080 when `shop.port` is not set anywhere.
    @Value(r'${shop.port:8080}') this.port,
    // A nullable target gets null when the property is missing.
    @Value(r'${shop.motto}') this.motto,
  );

  final String name;
  final Duration deliveryTime;
  final int port;
  final String? motto;

  // A comma-separated value becomes a list.
  @Value(r'${shop.tags}')
  late final List<String> tags;

  // SpEL: a placeholder inside an expression, then arithmetic.
  @Value(r'#{${shop.max-basket-size} * 2}')
  late final int warehouseLimit;
}
```

```dart
// SpEL can also read another bean by name: here the `shopProperties` bean
// (a @ConfigurationProperties class, which is introspected).
@Value('#{shopProperties.name.toUpperCase()}')
late final String banner;

// A location string becomes a Resource, read through the context's
// resource loader.
@Value('resources:templates/welcome.txt')
late final Resource welcomeTemplate;
```

What happens at startup:

- A non-nullable target without a value and without a default fails the start, with a message that names the key.
- A value that cannot be converted (`port=abc` for an `int`) fails the start too.
- A `conversionService` bean, if you declare one, is used for the conversion. See [ConversionService](../conversion/conversion-service.md).

## Parameters

| Name | Type | Default | Meaning |
|---|---|---|---|
| `value` | `String` | required | Text with `${...}` placeholders and/or `#{...}` expressions. Plain text is used as is. |

## In Spring (Java)

```java
@Service
class Shop {
  Shop(@Value("${shop.name}") String name,
       @Value("${shop.port:8080}") int port) { ... }

  @Value("${shop.tags}") List<String> tags;
  @Value("#{shopProperties.name.toUpperCase()}") String banner;
}
```

Differences that matter:

- In Dart, write the value as a raw string (`r'${shop.name}'`). A normal string `'${...}'` is Dart string interpolation and does not compile as intended.
- An optional value is a nullable type (`String?`), not `${x:#{null}}`.
- Spring checks lazy beans only when they are first used. Here `refresh()` also checks the placeholders of lazy beans, so a missing key fails at startup.
- SpEL reads only classes that have introspection metadata (`@Introspected`, or classes that get it automatically such as `@ConfigurationProperties`). There is no reflection.

## See also

- [Placeholders](placeholders.md)
- [@ConfigurationProperties](configuration-properties.md)
- [Environment](environment.md)
- [ConversionService](../conversion/conversion-service.md)
- [SpEL](../spel/index.md)
- [Beans](../beans/index.md)
