RESTEasy doesn't recognize custom message body writer
java, jax-rs, resteasy
Solution
Based on your code above it would appear that your `CSVMessageBodyWriter` is being called, but it is failing your `isWriteable` check.
Your `isWriteable` check is always going to return false. You are checking if `JaxbList` is assignable from `CSVSerializer`. This is always going to fail and your `CSVMessageBodyWriter` will not be deemed able to handle `text/csv`.
Try changing your isWriteable method to the following:
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType)
{
return true;
}
This will serialize all `text/csv` annotated methods. If you want to constrain it to `JaxbList` then you can do something like this:
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType)
{
ParameterizedType paramType = (ParameterizedType) genericType;
if(paramType.getRawType().equals(JaxbList.class))
{
return true;
}
return false;
}
Here is a simple working example of configuring a custom `MessageBodyWriter`:
Application
public class ProductGuideApplication extends Application
{
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> classes = new HashSet<Class<?>>();
public ProductGuideApplication()
{
singletons.add(new CSVMessageBodyWriter());
classes.add(FooResource.class);
}
@Override
public Set<Object> getSingletons()
{
return singletons;
}
@Override
public Set<Class<?>> getClasses()
{
return classes;
}
}
Resource
@Path("/foo")
public class FooResource
{
@GET
@Produces("text/csv")
public List<Consumer> getConsumers()
{
Consumer consumer1 = new Consumer();
consumer1.setId("1234");
consumer1.setGender("Male");
Consumer consumer2 = new Consumer();
consumer2.setId("2345");
consumer2.setGender("Male");
List<Consumer> consumers = new ArrayList<Consumer>();
consumers.add(consumer1);
consumers.add(consumer2);
return consumers;
}
}
MessageBodyWriter
@Provider
@Produces("text/csv")
public class CSVMessageBodyWriter implements MessageBodyWriter<List<Consumer>>
{
@Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType)
{
ParameterizedType paramType = (ParameterizedType) genericType;
if(paramType.getRawType().equals(List.class))
{
if(paramType.getActualTypeArguments()[0].equals(Consumer.class))
{
return true;
}
}
return false;
}
@Override
public long getSize(List<Consumer> t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType)
{
return 0;
}
@Override
public void writeTo(List<Consumer> t, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders,
OutputStream entityStream) throws IOException,
WebApplicationException
{
//Write your CSV to entityStream here.
}
}
Problem
My MessageBodyWriter ``` @Provider @Produces("text/csv") public class CSVMessageBodyWriter implements MessageBodyWriter<JaxbList> public static final String CONTENT_DISPOSITION_HEADER = "Content-Disposition"; //$NON-NLS-1$ private final static HeaderDelegate<ContentDispositionHeader> header = RuntimeDelegate.getInstance().createHeaderDelegate(ContentDispositionHeader.class); public long getSize(JaxbList t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return -1; } public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return CsvSerializer.class.isAssignableFrom(type); } public void writeTo(JaxbList t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { // set content disposition. This will enable browsers to open excel ContentDispositionHeader contentDispositionHeader = ContentDispositionHeader.createContentDispositionHeader(MediaTypeUtils.CSV_TYPE); contentDispositionHeader.setFileName("representation"); //$NON-NLS-1$ httpHeaders.putSingle(CONTENT_DISPOSITION_HEADER, header.toString(contentDispositionHeader)); Charset charset = Charset.forName(ProviderUtils.getCharset(mediaType)); OutputStreamWriter writer = new OutputStreamWriter(entityStream, charset); PrintWriter printWriter = new PrintWriter(writer); Iterator<String[]> rows = ((CsvSerializer) t).getEntities(); while (rows.hasNext()) { printWriter.println(CsvWriter.getCSVRow(rows.next())); } printWriter.flush(); } } ``` My REST Application ``` @Path("app/v3") @GZIP @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, "text/csv"}) public class ApplicationREST ``` Extension of Application ``` @ApplicationPath("/") public class JaxRsActivator extends Application { private Set<Object> singletons = new HashSet<Object>(); private Set<Class<?>> classes = new HashSet<Class<?>>(); public JaxRsActivator() { singletons.add(new CSVMessageBodyWriter()); classes.add(ApplicationREST.class); } @Override public Set<Object> getSingletons() { Set<Object> defaults = super.getSingletons(); singletons.addAll(defaults); return singletons; } public Set<Class<?>> getClasses() { return classes; } } ``` When I run in debug mode I can hit my JaxRsActivator class, so I know that the providers are being loaded. However I get the error "Could not find MessageBodyWriter for response object of type: net.comp.jaxb.JaxbList of media type: text/csv"