I am trying to read a CSV file whose header position numbers comes from a property file.
I get the position number for the fields using @Value. But however I am unable to bind this value as the position for @CsvBindByPosition
.
Here is my code :
public class MyPojo {
@Value(value = "${csv.pojo.refNumber}")
public static final int test;
@CsvBindByPosition(position = test)
private String id;
}
This gives me this error:
The value for annotation attribute
CsvBindByPosition.position
must be a constant expression
Is there a way to resolve this as my position needs to be read from a property file itself?
As suggested by MWiesner answer, annotation value can't be set in runtime.
What we need is some way to configure the column position mapping in runtime instead.
MappingStrategy
is the interface configure mapping between csv and bean.ColumnPositionMappingStrategy
is the implementation ready for use in this case.import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import com.opencsv.bean.ColumnPositionMappingStrategy;
import com.opencsv.bean.ColumnPositionMappingStrategyBuilder;
import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.StringReader;
@SpringBootTest(
classes = CsvByPositionInRuntimeTest.Pojo.class,
properties = {"csv.pojo.refNumber=0", "csv.pojo.name=1"}
)
public class CsvByPositionInRuntimeTest {
// assume 0
@Value("${csv.pojo.refNumber}")
private Integer refNumberIndex;
// assume 1
@Value("${csv.pojo.name}")
private Integer nameIndex;
// or specify column order like 'refNumber,name'
// this is more readable and easy to maintain
@Value("${csv.pojo.columnOrder}")
private String[] columnOrder;
@Test
public void parse() {
CSVReader csvReader = new CSVReaderBuilder(
new StringReader("""
123,david
456,terry
""")
).build();
ColumnPositionMappingStrategy<Pojo> positionMappingStrategy = new ColumnPositionMappingStrategyBuilder<Pojo>().build();
// this is just for demo, proper implementation is need for all column index
positionMappingStrategy.setColumnMapping(refNumberIndex < nameIndex ? new String[]{"refNumber", "name"} : new String[]{"name", "refNumber"});
// positionMappingStrategy.setColumnMapping(columnOrder);
positionMappingStrategy.setType(Pojo.class);
CsvToBean<Pojo> csvModelCsvToBean =
new CsvToBeanBuilder<Pojo>(csvReader).withMappingStrategy(
positionMappingStrategy
).build();
csvModelCsvToBean.parse().forEach(m -> System.out.println("id:%s ,name:%s".formatted(m.refNumber, m.name)));
}
public static class Pojo {
private String refNumber;
private String name;
}
}