如何使用OpenCSV或任何其他库将csv转换为嵌套bean?

时间:2018-11-14 21:25:40

标签: java csv parsing java-ee opencsv

我正在进行HTTP调用以获取CSV文件,并且我正在使用OpenCSV将等效于CSV文件的字符串转换为普通的旧Java对象。由于它包含敏感信息,因此我跳过了进行http调用以提取csv的逻辑。以下代码中转换后的Student对象的“ collegeTiming”属性具有空值。如何从CSV映射此值?有人可以建议吗?预先感谢!

PFB我对pom.xml的依赖

    <dependency>
        <groupId>com.opencsv</groupId>
        <artifactId>opencsv</artifactId>
        <version>4.0</version>
    </dependency>

我的输入CSV

"id", "name", "monday_open_time", "monday_close_time", "tuesday_open_time", "tuesday_close_time", "wednesday_open_time", "wednesday_close_time", "thursday_open_time", "thrusday_close_time", "friday_open_time", "friday_close_time"
1, ABCD, 07.00.00,21.00.00, 08.00.00,22.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00
2, ABCD, 08.00.00,21.00.00, 07.00.00,14.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00
3, ABCD, 07.00.00,21.00.00, 10.00.00,13.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00
4, ABCD, 09.00.00,21.00.00, 11.00.00,20.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00

我想将输入的csv转换为下面的Student bean

{
    "id" : 1,
    "name": ABC,
    "collegeTime" : { 
                        "monday":[ 07.00.00, 21.00.00 ], 
                        "tuesday":[ 08.00.00, 22.00.00 ], 
                        "wednesday":[ 07.00.00, 21.00.00 ], 
                        "thrusday":[ 07.00.00, 21.00.00 ], 
                        "friday":[ 07.00.00, 21.00.00 ], 
                        }

}

Student.java

import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.opencsv.bean.CsvBindByName;

public class Student {
@CsvBindByName
@JsonProperty("id")
private String id;
@JsonProperty("name")
@CsvBindByName
private String name;
@JsonProperty("collegeTiming")
private List<CollegeTiming> collegeTimings;

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public List<CollegeTiming> getCollegeTimings() {
    return collegeTimings;
}

public void setCollegeTimings(List<CollegeTiming> collegeTimings) {
    this.collegeTimings = collegeTimings;
}
}

CollegeTiming.java

import com.fasterxml.jackson.annotation.JsonProperty;

public class CollegeTiming {
@JsonProperty("collegeTime")    
private CollegeTime collegeTime;

public CollegeTime getCollegeTime() {
    return collegeTime;
}

public void setCollegeTime(CollegeTime collegeTime) {
    this.collegeTime = collegeTime;
}
}

CollegeTime.java

public class CollegeTime {
private String day;
private String startTime;
private String endTime;

public String getStartTime() {
    return startTime;
}

public void setStartTime(String startTime) {
    this.startTime = startTime;
}

public String getEndTime() {
    return endTime;
}

public void setEndTime(String endTime) {
    this.endTime = endTime;
}   

}

///使用OpenCSV将csv转换为Student对象。 注意:csvAsString是csv文件的字符串表示形式(我通过HTTP调用来获取此信息。

 HeaderColumnNameMappingStrategy<Student> strategy = new HeaderColumnNameMappingStrategy<>();
    strategy.setType(Student.class);

CsvToBean<Student> csvToBean = new CsvToBeanBuilder<Student>(new StringReader(csvAsString))
             .withType(Student.class)
             .withMappingStrategy(strategy)
             .withIgnoreLeadingWhiteSpace(true)
             .build();

 List<Student> = = csvToBean.parse();

当我打印Student对象时,将为Student对象的“ collegeTiming”属性打印null。如何将csv文件映射到嵌套对象(CollegeTime)?

2 个答案:

答案 0 :(得分:0)

这似乎有些奇怪,您正在尝试将平面数据推入层次结构。您将需要在此处进行一些自定义处理,因为您的密钥也与您要构建的模型不匹配。我已经举例说明了如何使用CSVReader和Jackson的ObjectMapper

public class CSVMappingTest {

    static String csv = "\"id\", \"name\", \"monday_open_time\", \"monday_close_time\", \"tuesday_open_time\", \"tuesday_close_time\", \"wednesday_open_time\", \"wednesday_close_time\", \"thursday_open_time\", \"thrusday_close_time\", \"friday_open_time\", \"friday_close_time\"\n" + 
            "1, ABCD, 07.00.00,21.00.00, 08.00.00,22.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00\n" + 
            "2, ABCD, 08.00.00,21.00.00, 07.00.00,14.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00\n" + 
            "3, ABCD, 07.00.00,21.00.00, 10.00.00,13.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00\n" + 
            "4, ABCD, 09.00.00,21.00.00, 11.00.00,20.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00";

    public static void main(String[] args) throws IOException {
        CSVReader reader = new CSVReader(new StringReader(csv));
        ObjectMapper mapper = new ObjectMapper();

        String[] keys = reader.readNext(); // headers
        String[] values = reader.readNext();
        while(values != null) {
            Student convertValue = mapper.convertValue(csvToMap(keys, values), Student.class);
            System.err.println(mapper.writeValueAsString(convertValue));
            values = reader.readNext();
        }
    }

    public static Map<String, String> csvToMap(final String[] headers, final String[] vals) {
        if(headers == null || vals == null) {
            throw new NullPointerException("Empty input for csv to map");
        }
        if(headers.length != vals.length) { 
            throw new IllegalArgumentException("Header and value count do not match for csv to map");
        }
        Map<String, String> res = new HashMap<>();
        IntStream.range(0, vals.length).forEach( i -> res.put(headers[i], vals[i]));
        return res;
    }

    public static class Student { 
        @JsonProperty("id")
        String id;
        @JsonProperty("name")
        String name;
        @JsonProperty
        Map<String, String> studentTimings = new HashMap<>();

        @JsonAnySetter
        public void setTime(String key, String value) { 
            studentTimings.put(key, value);
        }
    }
}

说明:

我仅使用CSVReader来检索行。

然后我使用csvToMap创建标头值的映射。

然后我在jackson上使用转换方法来自动创建我想要的bean。

重要的一点在这里:

    @JsonAnySetter
    public void setTime(String key, String value) { 
        studentTimings.put(key, value);
    }

这告诉杰克逊,任何未直接包装的财产都将被发送到这里。 在这里您可以处理时间,然后将其手动分组到所需的任何存储桶中。我看不到任何其他选择,因为您的平面输入与您尝试创建的属性不匹配。

OpenCSV和Jackson都不是处理器。他们不负责转换您的数据,其目的很简单,例如“找到密钥并呼叫设置程序”。您可以使用任何形式的自定义序列化程序来告诉它如何创建所需的对象,但是默认设置与上面的语句一样简单。

我肯定也有一个OpenCSV方法,但是我不知道:)

希望对您有帮助

Artur

P.s。我没有复制整个模型,而只是将值推到地图中。这样,我的解析输出将为:

{
  "id": "3",
  "name": " ABCD",
  "studentTimings": {
    "friday_close_time": "21.00.00",
    "friday_open_time": " 07.00.00",
    "monday_close_time": "21.00.00",
    "monday_open_time": " 07.00.00",
    "thrusday_close_time": "21.00.00",
    "thursday_open_time": " 07.00.00",
    "tuesday_close_time": "13.00.00",
    "tuesday_open_time": " 10.00.00",
    "wednesday_close_time": "21.00.00",
    "wednesday_open_time": " 07.00.00"
  }
}

答案 1 :(得分:0)

BufferedReader br = null;
List<Student> objLst = new ArrayList<Student>();
InputStreamReader inStreamReader = null;
inStreamReader = new 
InputStreamReader(ReadAccountsUtil.class.getClassLoader().getResourceAsStream("someFile.csv"));
CsvReader csvReader = new CsvReader(inStreamReader);
String objStr[] = {};
JavaPojoClass id = new Id();

    try {
        while (csvReader.readRecord()) {

            objStr = csvReader.getRawRecord().split(",");
            student = new Student();
            student.setRollNo(new Short(objStr[0]));
            student.setName(new String(objStr[1]));
            student.setAdd(new String(objStr[2]));
            student.setEmail(new String(objStr[3]));
            objLst.add(student);
        }
    } catch (Exception ex) {
        if(inStreamReader != null){
            try {
                inStreamReader.close();
            } catch (IOException e) {
                LOGGER.error("Error in closing the input streams"+ e.getMessage());
            }
        }
        LOGGER.error("Error in reading the Student file"+ ex.getMessage());
    }
    return objLst;
}