Skip to content
Advertisement

HttpMessageConverter for Single Object and List of Object

I have an Object (here: Property) and I want to add csv export ability to my Spring Backend for single and list of objects.

I added this to my config:

@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());
}

and the Property Converter looks like this:

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

This code works for a Single Property. When I try to return a list of Properties:

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]
    ....

I tried to add a PropertyListConverter but then it doesn’t work for Single Property. When I tried to add both, the first converter added is being used.

How can I make the Converter work for Single and List of Property (or any Object)

Advertisement

Answer

Does it work if you try adding the following method to your (single-property) converter?

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

The 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 AbstractGenericHttpMessageConverter class, adding an extra check on the class of the value to be written, so that it should only be used to write out Property values.

Note that the single-property converter should be added to the list of converters before the multi-property converter. Alternatively, make a similar modification to your multi-property converter too.

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement