Description
The default JSONProvider is trying to marshal a non-jaxb class which results in a 500 response of my endpoint.
One of my endpoints is returning a StreamingOutput object to the response object:
public static Response okJson(JValue json) { return Response.ok(new StreamingOutput() { @Override public void write(OutputStream s) throws IOException, WebApplicationException { try (final BufferedOutputStream bs = new BufferedOutputStream(s)) { serializer.fn.toJson(json).apply(bs); } } }, MediaType.APPLICATION_JSON_TYPE).build(); }
Unfortunately, the default JSONProvider is trying to marshal this class because it thinks it is a jaxb supported class. This support check happens in the AbstractJAXBProvider class:
protected boolean isSupported(Class<?> type, Type genericType, Annotation[] anns) { if (jaxbElementClassMap != null && jaxbElementClassMap.containsKey(type.getName()) || isSkipJaxbChecks()) { return true; } return isXmlRoot(type) || JAXBElement.class.isAssignableFrom(type) || objectFactoryOrIndexAvailable(type) || (type != genericType && objectFactoryForType(genericType)) || org.apache.cxf.jaxrs.utils.JAXBUtils.getAdapter(type, anns) != null; } protected boolean objectFactoryOrIndexAvailable(Class<?> type) { return type.getResource("ObjectFactory.class") != null || type.getResource("jaxb.index") != null; }
The issue is that the objectFactoryOrIndexAvailable is returning true which doesn't indicate that the type itself is a jaxb class. To fix the support method it should actually check if there is a jaxb.index file and if in the index file the current type is available. Then we can clearly say it's a jaxb supported class.
Something like this:
return isXmlRoot(type) || JAXBElement.class.isAssignableFrom(type) || (objectFactoryOrIndexAvailable(type) && indexContainsType(type)) || (type != genericType && objectFactoryForType(genericType)) || org.apache.cxf.jaxrs.utils.JAXBUtils.getAdapter(type, anns) != null; protected boolean indexContainsType(Class<?> type) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(type.getResourceAsStream("jaxb.index")))) { String line = null; while((line = reader.readLine()) != null) { if(line.contains(type.getName())) return true; } } return false; }