简体   繁体   中英

Java properties - Load into Map<String, AbstractMap.SimpleEntry<String, String>>

In Spring Boot project I have a Map<String, AbstractMap.SimpleEntry<String, String>> , and use it like:

testData.put("key1", new AbstractMap.SimpleEntry<>("myKey1", "myValue1");
testData.put("key2", new AbstractMap.SimpleEntry<>("myKey2", "myValue2");
...

I want to put the data into a Java properties file, to be more flexible to change it without changing the code, but how to construct the data in the properties file, to map it onto the Map?

I would have a class like:

@Component
@PropertySource("classpath:testdata.properties")
@ConfigurationProperties(prefix = "test.data")
public class TestDataProperties {
    private Map<String, AbstractMap.SimpleEntry<String, String>> testData;

    // Getter/Setter
}

When constructing in testData.properties , like:

test.data.testData.key1=myKey1,myValue1

and using it where needed with:

@Autowired
TestDataProperties testDataProperties;

I get Exceptions:

org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'test.data.testdata.key1' to java.util.AbstractMap$SimpleEntry<java.lang.String, java.lang.String>

org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [java.util.AbstractMap$SimpleEntry<java.lang.String, java.lang.String>]

Obviously a converter is needed, but how does one look like and how to wire it to the Map?

There are a couple of issue here -

  • First spring properties does not allow camel casing in the properties file, It will throw an exception when reading the properties file including camel casing.
  • There is no way you can capture property key inside a custom converter, spring will try to find the maching keyName inside your property class TestDataProperties , for the first key key1 it will try to find a field with key1 name.

Right now the program load the testData.properties and while parsing the properties file it is trying to look for the name key1 but there no key1, instead there is testData property thus testData is always nut in your code.

Since spring does not allow for camel casing properties you can update testData.properties like so (the convention is to use hyphen every time you want to used more that two words for a property name)-

test.data.test-data.key1=myKey1,myValue1

Then You can change you code in the following way -

TestDataProperties.java

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import java.util.AbstractMap;

@Component
@PropertySource(value = "classpath:testData.properties")
@ConfigurationProperties(prefix = "test.data.test-data")
public class TestDataProperties {

    private AbstractMap.SimpleEntry<String, String> key1;

    TestDataProperties(){

    }

    public AbstractMap.SimpleEntry<String, String> getKey1() {
        return key1;
    }

    public void setKey1(AbstractMap.SimpleEntry<String, String> key1) {
        this.key1 = key1;
    }
}

Secondly create custom converter to handle the data conversion while parsing the properties file -

CustomConverter.java

import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

import java.util.AbstractMap;

@Component
@ConfigurationPropertiesBinding
public class CustomConverter implements Converter<String, AbstractMap.SimpleEntry<String, String>> {


    @Override
    public AbstractMap.SimpleEntry<String, String> convert(String data) {
        if(data != null && !data.isEmpty()){
            String[] values = data.trim().split(",");
            if(values.length == 2){
                return new AbstractMap.SimpleEntry<>(values[0], values[1]);
            }
        }
        return null;
    }
}

Finally you can autowire your TestDataProperties class as

@Autowired
private TestDataProperties testDataProperties; 

Then you can access the properties like this -

testDataProperties.getKey1().getKey();
testDataProperties.getKey1().getValue();

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM