Spring
Value
Default Value
Java

Can I set null as the default value for a Value in Spring?

Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms

Introduction

Yes, you can set null as the default value for a @Value property in Spring, but not with the literal string null. The correct syntax uses Spring Expression Language (SpEL): @Value("${property.name:#{null}}"). This is the officially supported way to inject a true null reference when a property is missing.

The Problem: Why null Does Not Work Directly

When you write a default value in the @Value annotation, Spring treats it as a string literal. So "null" becomes the four-character string "null", not a Java null reference.

java
1// WRONG: someField gets the string "null", not null
2@Value("${some.property:null}")
3private String someField;
4// someField.equals("null") is true
5// someField == null is false

This catches many developers off guard because it looks correct at first glance.

The Solution: Use #{null} SpEL Expression

The #{null} syntax tells Spring to evaluate null as a SpEL expression, which produces an actual Java null:

java
// CORRECT: someField is null when some.property is not defined
@Value("${some.property:#{null}}")
private String someField;

This works because of how Spring processes the annotation:

  1. Spring first resolves ${some.property:#{null}} as a property placeholder.
  2. If some.property exists, its value is used.
  3. If some.property does not exist, the default #{null} is evaluated as a SpEL expression.
  4. SpEL evaluates null as Java's null.

Complete working example

java
1@Component
2public class NotificationService {
3
4    @Value("${notification.email.override:#{null}}")
5    private String emailOverride;
6
7    @Value("${notification.webhook.url:#{null}}")
8    private String webhookUrl;
9
10    @Value("${notification.retry.count:3}")
11    private int retryCount;
12
13    public void send(String message) {
14        if (emailOverride != null) {
15            sendEmail(emailOverride, message);
16        }
17        if (webhookUrl != null) {
18            sendWebhook(webhookUrl, message);
19        }
20    }
21}

In this example, both emailOverride and webhookUrl default to null when not configured, so the send method skips them naturally. No special string comparison needed.

Works With All Types, Not Just Strings

The #{null} default works with any object type:

java
1@Value("${cache.ttl.seconds:#{null}}")
2private Integer cacheTtl;  // null, not 0
3
4@Value("${feature.launch.date:#{null}}")
5private LocalDate launchDate;  // null, not some placeholder date
6
7@Value("${service.base.url:#{null}}")
8private URL serviceUrl;  // null, not a malformed URL

For primitive types (int, long, boolean), you cannot use #{null} because primitives cannot hold null. Use the wrapper types (Integer, Long, Boolean) instead.

java
1// WRONG: will throw at startup
2@Value("${some.count:#{null}}")
3private int count;  // primitives cannot be null
4
5// CORRECT: use the wrapper type
6@Value("${some.count:#{null}}")
7private Integer count;

Alternative Approaches

Using Optional<String> (Spring 4.3+)

Spring supports injecting Optional for properties that may not exist:

java
1@Value("${some.property:#{null}}")
2private Optional<String> someProperty;
3
4// Usage
5someProperty.ifPresent(value -> doSomething(value));

However, Optional as a field type is generally discouraged in Java. The #{null} approach with a nullable field is more idiomatic.

For applications with many optional properties, @ConfigurationProperties is cleaner than multiple @Value annotations:

java
1@ConfigurationProperties(prefix = "notification")
2public class NotificationProperties {
3
4    private String emailOverride;  // null by default
5    private String webhookUrl;     // null by default
6    private int retryCount = 3;    // explicit default
7
8    // getters and setters
9}

With @ConfigurationProperties, fields default to null naturally because that is Java's default for uninitialized object fields. No special syntax needed.

java
1@Service
2public class NotificationService {
3
4    private final NotificationProperties props;
5
6    public NotificationService(NotificationProperties props) {
7        this.props = props;
8    }
9
10    public void send(String message) {
11        if (props.getWebhookUrl() != null) {
12            sendWebhook(props.getWebhookUrl(), message);
13        }
14    }
15}

Post-processing with @PostConstruct

If you are stuck with an older Spring version that does not support #{null}, you can post-process the string:

java
1@Value("${some.property:__NULL__}")
2private String someField;
3
4@PostConstruct
5public void init() {
6    if ("__NULL__".equals(someField)) {
7        someField = null;
8    }
9}

This is a workaround, not a recommendation. Use #{null} when possible.

Comparison of Approaches

ApproachSyntaxProduces true nullComplexitySpring version
#{null} SpEL@Value("${prop:#{null}}")YesLow3.0+
@ConfigurationPropertiesClass field defaultsYesMedium4.0+
@PostConstruct workaroundCustom sentinel stringYes (after init)HighAny
Literal "null" string@Value("${prop:null}")No (it is a string)LowAny
Optional field@Value with Optional<T>N/A (uses Optional)Medium4.3+

How Spring Resolves @Value Defaults

Understanding the resolution order helps avoid surprises:

  1. Property sources are checked in order: system properties, environment variables, application.properties, application.yml, and any custom property sources.
  2. If the property exists, its value is used (converted to the field type via Spring's ConversionService).
  3. If the property does not exist, the default after the : is used.
  4. If no default is specified and the property is missing, Spring throws IllegalArgumentException at startup.
java
1// No default: fails at startup if missing
2@Value("${required.property}")
3private String required;
4
5// Default to null: starts fine even if missing
6@Value("${optional.property:#{null}}")
7private String optional;
8
9// Default to empty string: starts fine, but is "" not null
10@Value("${optional.property:}")
11private String emptyDefault;

The empty default (${}:}) is different from #{null}. An empty default gives you an empty string "", not null. Check which one your code actually needs.

Common Pitfalls

  • Using :null instead of :#{null}. This is the most common mistake. :null gives you the string "null". :#{null} gives you Java null.
  • Using #{null} with primitive types. int, long, boolean cannot hold null. Use Integer, Long, Boolean instead. Spring will throw a TypeMismatchException at startup.
  • Comparing with == instead of null check. If you accidentally use :null (wrong syntax), checking someField == null is always false because the field holds the string "null". This creates silent bugs.
  • Forgetting that an empty default is not null. @Value("${prop:}") sets the field to "", not null. If your code checks field != null, it passes but the field is empty.
  • Not providing any default for optional properties. Without a default, Spring fails at startup when the property is missing. Always provide a default for truly optional configuration.
  • Mixing @Value and @ConfigurationProperties in the same class. While technically allowed, it makes the configuration source confusing. Pick one approach per class.

Summary

  • Use @Value("${property:#{null}}") to get a true Java null default. The #{null} part is a SpEL expression, not a string literal.
  • Never use @Value("${property:null}") because that produces the string "null", not null.
  • The #{null} syntax works with any object type: String, Integer, LocalDate, URL, etc.
  • For primitive types (int, long, boolean), use their wrapper classes since primitives cannot be null.
  • For complex configurations with many optional fields, prefer @ConfigurationProperties where fields are null by default.
  • Always distinguish between "null" (property absent), empty string (property present but blank), and a default value (property absent, fallback provided).

Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms