2

I have the following:

app.properties

indexes=1,2;2,3;3,4

I'd like to bind these properties to List<Index>, but can't figure out the proper SpEL syntax.

Index.java

public class Index {

    public Index(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

Right now I'm splitting the values within constructor by semicolon delimiter then building a list.

Service.java

...
List<Index> indexList;

public Service(@Value(value = "#{'${indexes}'.split(';')}") 
               List<String> properties) {

        List<Index> result = new ArrayList<>();

        for (String s : properties) {
            String[] split = s.split(",");
            Index index = new Index(Integer.valueOf(split[0]), Integer.valueOf(split[1]));
            result.add(index);
    }

    this.indexList = result;
}

Can I do that with a single line? Like:

@Value(value = "some_spring_magic")
List<Index> indexList;
Mikhail Kholodkov
  • 23,642
  • 17
  • 61
  • 78
  • https://stackoverflow.com/questions/12576156/reading-a-list-from-properties-file-and-load-with-spring-annotation-value ? – StanislavL Nov 12 '19 at 14:28

2 Answers2

0

Replace ; with , like this:

@Value(value = "#{'${indexes}'.replaceAll(';',',').split(',')}")

Another idea can be to use a splitter utility, like this:

package foo;

import java.util.stream.Stream;

public class Splitter {

    public static String[] split(String str, String delimeters){
        Stream<String> s = Stream.of(str);
        for (int i = 0; i < delimeters.length(); i++) {
            String delimiter = delimeters.substring(i, i+1);
            s = s.flatMap(r -> Stream.of(r.split(delimiter)));   
        }
        return s.toArray(String[]::new);
    }
}

And then:

@Value(value = "#{T(foo.Splitter).split('${indexes}', ';,')}")
List<String> properties;
David Pérez Cabrera
  • 4,960
  • 2
  • 23
  • 37
0

I think that there are no need building complicated expression in SpEL. You can pass only value and process into the expected list as a bean. For example:

@Configuration
public class AppConfig {

    @Bean
    List<Index> indexList(@Value("${indexes}") String indexList) {
        return Arrays.asList(indexList.split(";"))
                .stream().map(s -> {
                    String[] split = s.split(",");
                    return new Index(Integer.valueOf(split[0]), Integer.valueOf(split[1]));
                }).collect(Collectors.toList());
    }

Later it can be used as below:

@Autowired
List<Index> indexList;
lczapski
  • 4,026
  • 3
  • 16
  • 32