【发布时间】:2020-03-30 22:25:15
【问题描述】:
我正在尝试使用 Spring 的 RestTemplate 将远程 CSV 文件解析为 bean。我想使用RestTemplate 的原因是它已经解决了 Http-Connection 的所有低级问题(主要是资源管理),我可以轻松地设置超时。
所以我编写了一个自定义的HttpMessageConverter,它使用 OpenCSV 将 HttpMessage 转换为 CSV bean。该 bean 使用 OpenCSV 的相应 CsvToBean 注释进行注释。然而,问题是 RestTemplate 提供的正是您在 Class-Parameter 中指定的内容。
restTemplate.exchange("www.exmample.com", HttpMethod.GET, null, MyDTO.class)
上面的代码总是返回一个 MyDTO。如果您想要一个 MyDTO 列表,那么您必须使用 RestTemplate 来指定:
restTemplate.exchange("www.exmample.com", HttpMethod.GET, null, MyDTO[].class)
然而,OpenCSV 的工作方式有所不同。
final CsvToBeanBuilder<MyDTO> beanBuilder = new CsvToBeanBuilder<>(new InputStreamReader(httpInputMessage.getBody()));
beanBuilder.withType(MyDTO.class); // not sure of this is needed
beanBuilder.build().parse(); // returns List<MyDTO>
因此,OpenCSV 采用 DTO 的单数、非数组版本,并且它的 parse-it-all 函数返回给定内容的列表。问题是我在我的自定义 HttpMessageConverter 中使用 OpenCSV。所以我不得不使用从 RestTemplate 获得的 Class 类型:
// Inside of my class that extends HttpMessageConverter<T>
@Override
public T read(final Class<? extends T> aClass, final HttpInputMessage httpInputMessage)
throws IOException, HttpMessageNotReadableException {
final CsvToBeanBuilder<T> beanBuilder = new CsvToBeanBuilder<>(new InputStreamReader(httpInputMessage.getBody()));
beanBuilder.withType(aClass); // This throws an exception if aClass is of MyDTO[].class.
// The exception states that there is no way to init the class.
// This returns a List<Class<T>> which is already wrong. This findFirst() workaround could work but it fails earlier
return beanBuilder.build().parse().stream().findFirst().orElse(null);
}
我能想到的唯一解决方案是将我真正想要的类硬编码到我的自定义 HttpMessageConverter 中。我想避免这种情况,因为这个消息转换器对项目的其余部分没有可重用性。 这个问题还有其他解决方案吗?
【问题讨论】: