79479270

Date: 2025-03-02 14:57:47
Score: 2
Natty:
Report link

1. Why does @Value("${kis.appsecret[0]}") work, but List<String> does not?

It seems like List<String> in @ConfigurationProperties should bind correctly, but for some reason, it doesn’t work with environment variables. Meanwhile, @Value("${kis.appsecret[0]}") works just fine.

Why is that?

When Spring tries to bind a list, it expects environment variables to be indexed starting from zero, like this:

KIS_APPKEY_0=value1
KIS_APPKEY_1=value2

But if your environment variables start from 1 instead of 0, like this:

KIS_APPKEY_1=value1
KIS_APPKEY_2=value2

Spring won’t recognize them as a list. Instead, it will interpret KIS_APPKEY_1 as an independent property rather than an element of an array, causing the binding to fail.

With @Value("${kis.appsecret[0]}"), Spring is simply fetching a single value instead of trying to construct a list, so there’s no issue.

2. Why do error logs start with kis.appkey[1] instead of [0]?

This happens because Spring expects the first element of a list to have the index 0 (kis.appkey[0]). If the environment variables only contain KIS_APPKEY_1 and KIS_APPKEY_2, Spring won’t recognize them as a list.

Essentially, Spring thinks:

*“Hmm… I didn’t receive kis.appkey[0], but I do see kis.appkey[1]. Something must be missing.”*

That’s why the error log shows the missing index.

3. Why does the same code work in Spring Boot 3.4.3 but not in 3.4.0?

Most likely, Spring Boot 3.4.3 introduced some improvements in how it handles list bindings from environment variables. Such changes are not always well-documented, but they can affect application behavior. If upgrading to 3.4.3 solves the issue, it’s likely due to a bug fix or an enhancement in the binding mechanism.

4. How to fix it?

Option 1: Use an array (String[]) instead of List<String>

Spring sometimes binds arrays better than lists. Try changing List<String> to String[] in KisProperties:

@Component
@ConfigurationProperties(prefix = "kis")
@Getter
@Setter
@ToString
public class KisProperties {
    private String domain;
    private String webSocketDomain;
    private String[] appkey;
    private String[] appsecret;
}

If list binding fails, switching to an array might work.

Option 2: Use a comma-separated (CSV) format

If you can control the environment variables, try defining them as a comma-separated string:

KIS_APPKEY=appkey1,appkey2
KIS_APPSECRET=secret1,secret2

Then, in application.yml:

kis:
  appkey: ${KIS_APPKEY:appkey1,appkey2}
  appsecret: ${KIS_APPSECRET:secret1,secret2}

Spring will automatically split "appkey1,appkey2" into a list.

Option 3: Ensure environment variables start from [0]

If you can modify the environment variables, explicitly define:

KIS_APPKEY_0=appkey1
KIS_APPKEY_1=appkey2

This ensures Spring properly recognizes them as a list.

Option 4: Manually bind the values using @PostConstruct

If the environment variables are already set and cannot be changed, manually extract them in the constructor:

@Component
@ConfigurationProperties(prefix = "kis")
@Getter
@Setter
@ToString
public class KisProperties {
    private String domain;
    private String webSocketDomain;
    private List<String> appkey;
    private List<String> appsecret;

    @PostConstruct
    public void init() {
        if (appkey == null || appkey.isEmpty()) {
            appkey = Arrays.asList(System.getenv("KIS_APPKEY_1"), System.getenv("KIS_APPKEY_2"));
        }
        if (appsecret == null || appsecret.isEmpty()) {
            appsecret = Arrays.asList(System.getenv("KIS_APPSECRET_1"), System.getenv("KIS_APPSECRET_2"));
        }
    }
}

This approach manually loads environment variables into a List.

Reasons:
  • RegEx Blacklisted phrase (1.5): How to fix it?
  • RegEx Blacklisted phrase (0.5): Why is that
  • Long answer (-1):
  • Has code block (-0.5):
  • Contains question mark (0.5):
  • Low reputation (1):
Posted by: Maksim Banit