在我的 Spring Boot 应用程序中,我有一个被注入到 Service 类中的 CsvMapper。此 CsvMapper 被定义为配置文件中的 bean。
在我的控制器中,当我返回通过传入 HashMap 创建的 ResponseEntity 时,堆栈跟踪会显示这些错误。
w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Unrecognized column 'message': known columns: ]; nested exception is com.fasterxml.jackson.dataformat.csv.CsvMappingException: Unrecognized column 'message': known columns: ] (through reference chain: java.util.HashMap["message"])]
w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Unrecognized column 'timestamp': known columns: ]; nested exception is com.fasterxml.jackson.dataformat.csv.CsvMappingException: Unrecognized column 'timestamp': known columns: ] (through reference chain: java.util.LinkedHashMap["timestamp"])]
这是这些文件的简要布局。
CsvParserService
@Slf4j
@Component
public final class CsvParserService {
private CsvMapper csvMapper;
// TODO: This injection causes a problem when creating a ResponseEntity(Map,...). Investigate why this is happening
public CsvParserService(@Qualifier("myCsvMapper") CsvMapper myCsvMapper) {
this.csvMapper = myCsvMapper;
}
public <T> List<T> parseCsvFile(Class<T> modelClass, MultipartFile csvFile, boolean ifHeader) throws IOException {
// create inputStream of the scorecard CSV file
InputStream fileStream = new BufferedInputStream(csvFile.getInputStream());
CsvSchema csvSchema = csvMapper
.typedSchemaFor(modelClass)
.withUseHeader(ifHeader) // this should be configured applied based on the queryParameter value in the PostRequest
.withColumnSeparator(',')
.sortedBy("timestamp", "productName", "a", "b", "c", "d", "e", "f", "g", "h", "j", "k");
MappingIterator<T> iterator = csvMapper
.readerWithTypedSchemaFor(modelClass)
.with(csvSchema)
.readValues(fileStream);
return iterator.readAll();
}
定义bean的配置文件
@Configuration
public class JacksonConfig {
@Bean(name="myCsvMapper")
public CsvMapper myCsvMapper(DateTimeFormatter dateTimeFormatter) {
JavaTimeModule javaTimeModule = new JavaTimeModule();
configureDateTimeDeSerialization(javaTimeModule, dateTimeFormatter);
CsvMapper csvMapper = new CsvMapper();
csvMapper.registerModule(javaTimeModule);
return csvMapper;
}
private void configureDateTimeDeSerialization(JavaTimeModule javaTimeModule, DateTimeFormatter dateTimeFormatter) {
// Instant customizations
javaTimeModule.addSerializer(Instant.class, new JsonSerializer<>() {
@Override
public void serialize(Instant value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString(dateTimeFormatter.format(value));
}
});
javaTimeModule.addDeserializer(Instant.class, new JsonDeserializer<>() {
@Override
public Instant deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
return dateTimeFormatter.parse(p.getText(), Instant::from);
}
});
// Instant customizations for map keys
javaTimeModule.addKeySerializer(Instant.class, new JsonSerializer<>() {
@Override
public void serialize(Instant value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeFieldName(dateTimeFormatter.format(value));
}
});
javaTimeModule.addKeyDeserializer(Instant.class, new KeyDeserializer() {
@Override
public Object deserializeKey(String key, DeserializationContext ctxt) {
return dateTimeFormatter.parse(key, Instant::from);
}
});
}
发生错误的控制器在“return new...”的行上
@RepositoryRestController
@RequestMapping("/api/v1")
public class ScorecardSummaryController {
@ResponseBody
@GetMapping(value = {"/csvmapper"})
public ResponseEntity<?> getProducts() {
// some services calls
Map<String, String> map = new HashMap<String, String>();
map.put("message", "Some message");
map.put("status", "Ok");
return new ResponseEntity<>(map, HttpStatus.OK); // error occurs after this line
}
}
我怀疑 CsvMapper bean 已经成为应用程序的默认映射器?但我不确定这是如何发生的,或者为什么在通过传入 HashMap 创建 ResponseEntity 时会发生这种情况。如果我以其他方式创建 ResponseEntity,例如
return new ResponseEntity<String>("Success", HttpStatus.OK);
,它不会返回任何错误。如果我在 @Bean 定义中编写代码来忽略未知列的错误,则当我点击 API 端点时应用程序不会返回任何内容。
我也遇到过同样的问题。 CsvMapper 难以置信地扩展了 ObjectMapper:https://fasterxml.github.io/jackson-dataformats-text/javadoc/csv/2.10/com/fasterxml/jackson/dataformat/csv/CsvMapper.html。 当您创建 CsvMapper bean 时,Spring MVC 在进行 JSON 反/序列化时将使用它而不是它自己的 ObjectMapper。 您有两种选择来解决此问题: