javaspring-bootspring-elspring-cache

Object became null in @CachePut annotation


For some reason I can see that object was passed not null, but in key expression it is null already.

I am trying to read some data from DB and add it to the cache. Here are my methods.

public void preloadCache() {
        List<Statistic> allData = repository.findAll();
        log.info("Data found {}", allData.size());
        allData.forEach(cacheService::populateQuarterStatisticCache);
}

It calls separate service

@Service
@Slf4j
public class CacheService {

    @CachePut(value = "quarterStatistic", key = "#statistic.type + '-' + #statistic.location")
    public QuarterBusinessesStatistic populateQuarterStatisticCache(Statistic statistic) {
        log.info("Loading statistic into cache: {}-{}", statistic.getType(), statistic.getLocation());
        return statistic.getData();
    }
}

Logs shows me that there is one object and it is not null

[nio-8080-exec-1] StatisticClient     : Data found 1
[nio-8080-exec-1] CacheService     : Preloading statistic into cache: restaurant-New York

But next line of the log tells me SpelEvaluationException: EL1007E: Property or field 'type' cannot be found on null

If I am changing key in my @CachePut annotation to key = "#statistic?.type + '-' + #statistic?.location" there will be no exceptions. But in the cache I will see stored object by null-null key

I can debug it and see that my object is not null. Logs also prove that. But in key expression it is null for some reason.

Does anybody had the same?

Note: I tried to change key to something like #statistic.getType() + '-' + #statistic.getLocation() - same result

My pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>MyService</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>21</java.version>
        <spring-boot.version>3.3.5</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.13.0</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Solution

  • From the comments it is apparent that positional parameters, #a0 do work and named parameters #statistic fails. This is an indication that your maven-compiler-plugin isn't setup properly.

    From your pom.xml your maven-compiler-plugin is configured as follows:

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.13.0</version>
        <configuration>
            <source>${java.version}</source>
            <target>${java.version}</target>
        </configuration>
    </plugin>
    

    Now with Spring Boot 3 (or rather Spring Framework 6.1) is is needed to enable compilation with parameter name retention. You need to configure this in your maven-compiler-plugin.

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.13.0</version>
        <configuration>
            <release>${java.version}</release>
            <parameters>true</parameters>
        </configuration>
    </plugin>
    

    This will keep the parameter names in the class file and will make #statistic work.

    An easier way is, as you are using Spring Boot, is to remove this maven-compiler-plugin al together and use the spring-boot-starter-parent which does all of this (and more) already.

    <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>3.3.5</version>
    </parent>