12

In a spring project, I'd like to create a LocalDate from an @Autowired constructor parameter whose value is in a .properties file. Two things I'd like to do:

1. If the property file contains the property my.date, the parameter should be created by parsing the property value

When the property is set, and when I use the following:

@DateTimeFormat(pattern = "yyyy-MM-dd") @Value("${my.date}") LocalDate myDate,
...

I get this error: java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.time.LocalDate': no matching editors or conversion strategy found

I have also used the iso = ... to use an ISO date with the same result.

2. If the property is not in the properties file, the parameter should be created using LocalDate.now()

I tried using a default value as such:

@Value("${my.date:#{T(java.time.LocalDate).now()}}") LocalDate myDate,
...

But I get the same error.

Forgive my ignorance with Spring, but how can I achieve the two objectives here?

Amine Safi
  • 255
  • 4
  • 8
Josh
  • 4,726
  • 2
  • 20
  • 32

7 Answers7

23

I know two ways. One is generic for any object - to use @Value annotation on custom setter

@Component
public class Example {

    private LocalDate localDate;

    @Value("${property.name}")
    private void setLocalDate(String localDateStr) {
        if (localDateStr != null && !localDateStr.isEmpty()) {
            localDate = LocalDate.parse(localDateStr);
        }
    }
}

The second is for LocalDate/LocalDateTime

public class Example {
    @Value("#{T(java.time.LocalDate).parse('${property.name}')}")
    private LocalDate localDate;
}

Sample property:

property.name=2018-06-20
wltheng
  • 750
  • 1
  • 11
  • 26
Pavel
  • 2,557
  • 1
  • 23
  • 19
13

Spring Boot 2.5, works perfect:

application.yaml

my.date: 2021-08-14
my.time: "11:00"
@Service
public class TestService {
    @Value("${my.date}")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    LocalDate myDate;

    @Value("${my.time}")
    @DateTimeFormat(iso = DateTimeFormat.ISO.TIME)
    LocalTime myTime;
}
Grigory Kislin
  • 16,647
  • 10
  • 125
  • 197
  • 1
    You probably wanted to point out the two possible options to specify the pattern, but obviously, we can also use the `DateTimeFormat.ISO` constant for the LocalDate, like `@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)` – mmey Sep 19 '22 at 06:53
2

If you want to specify the date format as well then use following on the field:

@Value("#{T(java.time.LocalDate).parse('${date.from.properties.file}', T(java.time.format.DateTimeFormatter).ofPattern('${date.format.from.properties.file}'))}")
Rakesh
  • 4,004
  • 2
  • 19
  • 31
1

Try to add this into your properties file:

spring.jackson.date-format=com.fasterxml.jackson.databind.util.ISO8601DateFormat
spring.jackson.time-zone=UTC

and remove @DateTimeFormat annotation

Concerning LocalDate.now() initialization. Try to use field injection this way:

@Value("${my.date}") LocalDate myDate = LocalDate.now();
luboskrnac
  • 23,973
  • 10
  • 81
  • 92
0

As mentioned in other answer by Pavel there are two ways.

I am providing similar two ways with modification to handle 2nd Point by OP.

If the property is not in the properties file, the parameter should be created using LocalDate.now()

@Component
public class Example {

private LocalDate localDate;

@Value("${property.name}")
private void setLocalDate(String localDateStr) {
    if (localDateStr != null && !localDateStr.isEmpty()) {
        localDate = LocalDate.parse(localDateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }else{
        localDate = LocalDate.now();
    }
}
}

I Prefere 2nd way though...

public class Example {
    @Value("#{T(java.time.LocalDate).parse('${property.name}', T(java.time.format.DateTimeFormatter).ofPattern('yyyy-MM-dd')) ?: T(java.time.LocalDate).now()}")
    private LocalDate localDate;
}

Edit:- Fixed 2nd Way

@Value("#{ !('${date:}'.equals('')) ? T(java.time.LocalDate).parse('${date:}', T(java.time.format.DateTimeFormatter).ofPattern('MM-dd-yyyy')) " +
        ":T(java.time.LocalDate).now()}")
private LocalDate asOfDate;
rahul maindargi
  • 5,359
  • 2
  • 16
  • 23
  • When I try the above I get: IllegalArgumentException: Could not resolve placeholder 'startDate' in value "#{T(java.time.LocalDateTime).parse('${startDate}', T(java.time.format.DateTimeFormatter).ofPattern('yyyy-MM-dd HH:mm:ss')) ?: T(java.time.LocalDateTime).now()}" thoughts? – Jim M. Aug 08 '19 at 20:23
  • @JimM. Fixed the answer... please check. – rahul maindargi Aug 11 '19 at 12:09
0

For the first bit, you could create a converter:

@Component
@ConfigurationPropertiesBinding
public class LocalDateConverter implements Converter<String, LocalDate> {

  @Override
  public LocalDate convert(String s) {
    if (s == null) {
        return null;
    }
    return LocalDate.parse(s);
  }
}

Your config Class will automatically use this for conversion.

For the 2nd you can just do:

if(my.date == null) iso = LocalDate.now()
Scott
  • 11
  • 2
0

There's an example of initializing a LocalDateTime value using annotations and configuration properties. I've tested that it works in Spring Boot 2.4.

MyComponent.kt fragment:

@Value("\${my.date}")
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
val myDate: LocalDateTime

application.yml:

my:
  date: "2023-01-23T00:00:00"
naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259