用于单个对象和对象列表的 HttpMessageConverter

HttpMessageConverter for Single Object and List of Object

我有一个对象(此处:属性),我想将 csv 导出功能添加到我的 Spring 后端,用于单个对象和对象列表。

我将此添加到我的配置中:

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer.(more config).mediaType("csv", new MediaType("text", "csv"));
}

@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
     converters.add(new PropertyConverter());
     converters.add(new StatsConverter());
}

并且 属性 转换器如下所示:

public class PropertyConverter extends AbstractGenericHttpMessageConverter<Property> {

    private static final Logger LOGGER = LoggerFactory.getLogger(PropertyConverter.class);

    public PropertyConverter() {
        super(new MediaType("text", "csv"));
    }

    @Override
    protected void writeInternal(Property property, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        try (var writer = new OutputStreamWriter(outputMessage.getBody())) {
            new StatefulBeanToCsvBuilder<>(writer).withSeparator(',').build().write(property);
        } catch (CsvDataTypeMismatchException | CsvRequiredFieldEmptyException ex) {
            LOGGER.error("CSV failed to convert property: ".concat(property.getExternalId()).concat(", exception: ".concat(ex.toString())));
        }
    }

    @Override
    protected Property readInternal(Class<? extends Property> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        return null;
    }

    @Override
    public Property read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        return null;
    }
}

此代码适用于单个 属性。当我尝试 return 属性列表时:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class eu.webeng.model.Property (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; eu.webeng.model.Property is in unnamed module of loader 'app')
    ...

Caused by: java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class eu.webeng.model.Property (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; eu.webeng.model.Property is in unnamed module of loader 'app')
    at eu.webeng.converter.PropertyConverter.writeInternal(PropertyConverter.java:20) ~[classes/:na]
    at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:104) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:287) ~[spring-webmvc-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:219) ~[spring-webmvc-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    ....

我尝试添加一个 属性ListConverter,但它对 Single 属性 不起作用。当我尝试添加两者时,正在使用第一个添加的转换器。

如何使转换器适用于 属性(或任何对象)的单个和列表

如果您尝试将以下方法添加到您的 (single-property) 转换器是否有效?

    @Override
    public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
        return super.canWrite(clazz, mediaType) && clazz == Property.class;
    }

AbstractMessageConverterMethodProcessor class loops through all registered converters and skips any for which the canWrite method returns false. I've adapted the method above from the AbstractGenericHttpMessageConverterclass,对要写入的值class添加额外的检查,使其只应该用于写出Property值。

请注意,single-property 转换器应在 multi-property 转换器之前添加到转换器列表中。或者,也对您的 multi-property 转换器进行类似的修改。