Как преобразовать CSV в вложенные бины, используя OpenCSV или любую другую библиотеку? - PullRequest
0 голосов
/ 15 ноября 2018

Я делаю 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 в ниже студенческий бин

{
    "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;
}   

}

// Преобразование CSV в объект Student с использованием OpenCSV. Примечание: 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, ноль печатается для свойства «CollegeTiming» объекта Student. Как сопоставить CSV-файл с вложенным объектом (CollegeTime)?

Ответы [ 2 ]

0 голосов
/ 15 ноября 2018
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;
}
0 голосов
/ 15 ноября 2018

Это кажется немного странным, вы пытаетесь поместить плоские данные в иерархию.Там вам нужно будет выполнить некоторую пользовательскую обработку, поскольку ваши ключи также не соответствуют модели, которую вы пытаетесь построить.Я привел пример того, как этого добиться, используя CSVReader и Джексона 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 для создания сопоставления значения заголовка.

Затем я использую метод преобразования в Джексоне для автоматического создания нужного компонента.

Важный бит здесь:

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

Это говорит Джексону, что любое свойство, не обернутое напрямую, будет отправлено сюда.Здесь вы можете обработать свое время и вручную сгруппировать его в те корзины, которые вам нужны.Я не вижу другой альтернативы, поскольку ваш плоский ввод не соответствует свойствам, которые вы пытаетесь создать.

Ни OpenCSV, ни Джексон не являются процессорами.Они не несут ответственности за преобразование ваших данных, их цель так же проста, как «найти ключ и вызвать установщика».Вы можете использовать настраиваемый сериализатор любой формы, чтобы указать ему, как создавать нужные объекты, но по умолчанию все так же просто, как и в приведенном выше утверждении.

Я уверен, что для этого тоже есть метод OpenCSV, но я его не знаю :)

Надеюсь, это поможет,

Артур

Ps Я не копировал всю вашу модель, а просто поместил значения в карту.Результат моего анализа будет, например, таким:

{
  "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"
  }
}
...