Java Programming Tutorials

Java programming tutorials with many code examples!

Spring inject null value

Problem:

How to inject null value in Spring Framework? This can be easily done using Spring Expression Language as in the following example.

Solution:

Obligatory project configuration. We use Gradle, so here’s build.gradle:

buildscript {
    repositories {
        jcenter()
        maven { url "http://repo.spring.io/snapshot" }
        maven { url "http://repo.spring.io/milestone" }
    }
    dependencies {
        // Provides tasks to create executable JAR and run project from source.
        // It also adds ResolutionStrategy, which allows to ommit versions in
        // "blessed" dependencies below.
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.2.3.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'spring-boot'

jar {
    baseName = 'spring-tutorial'
    version =  '0.0.1-SNAPSHOT'
}

repositories {
    jcenter()
    maven { url "http://repo.spring.io/snapshot" }
    maven { url "http://repo.spring.io/milestone" }
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter")
    testCompile("org.springframework.boot:spring-boot-starter-test")
}

Simple Spring Boot application with minimal Spring Application Context that injects two values into our imaginary BookService:

package com.farenda.spring.tutorial;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;

@EnableAutoConfiguration
// Parameters can be passed from command line:
// --owner=Farenda --open=true
// or loaded from properties like so:
//@PropertySource("classpath:my-app.properties")
public class MyAppSpringContext {

    @Service
    public static class BookService {

        @Value("${owner:#{null}}")
        private String owner;

        @Value("${open:false}")
        private boolean open;

        public String getOwner() {
            return owner != null ? owner : "No owner";
        }

        public boolean isOpen() {
            return open;
        }
    }

    public static void main(String[] args) {
        ApplicationContext context =
                SpringApplication.run(MyAppSpringContext.class, args);
        BookService bookService = context.getBean(BookService.class);
        System.out.printf("Book Service owner: %s, is open: %b%n",
                bookService.getOwner(), bookService.isOpen());
    }
}

@Value annotation refers to properties or command line using ${propertyName} syntax.

If you try to inject a property that’s not available in application context (for example @Value(“${owner}”)), then Spring will throw *IllegalArgumentException: Could not resolve placeholder ‘owner’ in string value “${owner}”*.

To inject a default value you can pass it after property name, like so: @Value(“${owner:0}”).

The problem is when you want to inject null as default value. If you try to use @Value(“${owner:null}”) then Spring will treat it literally and inject *”null”* string, which can lead to unexpected results! Here passing no owner argument will initialize it with “null” string and won’t return No owner as expected. Yay!

To inject null as default value you have to use Spring Expression Language like so: @Value(“${owner:#{null}}”). Now Spring Framework will inject null reference not a “null” string value:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.2.3.RELEASE)

2015-08-27 21:19:23.495  INFO 6709 --- [           main] c.f.spring.tutorial.MyAppSpringContext   : Starting MyAppSpringContext on namek with PID 6709 (/farenda/spring-tutorial/build/classes/main started by farenda in /farenda/spring-tutorial)
2015-08-27 21:19:23.553  INFO 6709 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@7a187f14: startup date [Thu Aug 27 21:19:23 CEST 2015]; root of context hierarchy
2015-08-27 21:19:25.135  INFO 6709 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2015-08-27 21:19:25.157  INFO 6709 --- [           main] c.f.spring.tutorial.MyAppSpringContext   : Started MyAppSpringContext in 2.138 seconds (JVM running for 2.932)
Book Service budget: No owner, is open: false
2015-08-27 21:19:25.160  INFO 6709 --- [       Thread-1] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@7a187f14: startup date [Thu Aug 27 21:19:23 CEST 2015]; root of context hierarchy
2015-08-27 21:19:25.165  INFO 6709 --- [       Thread-1] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown

Running the program with arguments –owner=Farenda –open=true prints:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.2.3.RELEASE)

2015-08-27 21:07:25.440  INFO 6370 --- [           main] c.f.spring.tutorial.MyAppSpringContext   : Starting MyAppSpringContext on namek with PID 6370 (/farenda/spring-tutorial/build/classes/main started by farenda in /farenda/spring-tutorial)
2015-08-27 21:07:25.493  INFO 6370 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@27808f31: startup date [Thu Aug 27 21:07:25 CEST 2015]; root of context hierarchy
2015-08-27 21:07:26.890  INFO 6370 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2015-08-27 21:07:26.907  INFO 6370 --- [           main] c.f.spring.tutorial.MyAppSpringContext   : Started MyAppSpringContext in 1.926 seconds (JVM running for 2.746)
Book Service owner: Farenda, is open: true
2015-08-27 21:07:26.913  INFO 6370 --- [       Thread-1] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@27808f31: startup date [Thu Aug 27 21:07:25 CEST 2015]; root of context hierarchy
2015-08-27 21:07:26.914  INFO 6370 --- [       Thread-1] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown

Nice feature of Spring Boot is that we can pass command line arguments to it. Spring Boot then parses them and injects into beans in application context.

Share with the World!