package org.springframework.data.web;
import java.io.IOException;
import java.util.Map;
import javax.annotation.Nullable;
import javax.xml.parsers.DocumentBuilderFactory;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.xml.sax.SAXParseException;
import org.xmlbeam.XBProjector;
import org.xmlbeam.config.DefaultXMLFactoriesConfig;
public class XmlBeamHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
private final XBProjector projectionFactory;
private final Map<Class<?>, Boolean> supportedTypesCache = new ConcurrentReferenceHashMap<>();
public XmlBeamHttpMessageConverter() {
this(new XBProjector(new DefaultXMLFactoriesConfig() {
private static final long serialVersionUID = -1324345769124477493L;
@Override
public DocumentBuilderFactory createDocumentBuilderFactory() {
DocumentBuilderFactory factory = super.createDocumentBuilderFactory();
factory.setAttribute("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setAttribute("http://xml.org/sax/features/external-general-entities", false);
return factory;
}
}));
}
public XmlBeamHttpMessageConverter(XBProjector projector) {
super(MediaType.APPLICATION_XML, MediaType.parseMediaType("application/*+xml"));
Assert.notNull(projector, "XBProjector must not be null!");
this.projectionFactory = projector;
}
@Override
protected boolean supports(Class<?> type) {
Class<?> rawType = ResolvableType.forType(type).resolve(Object.class);
Boolean result = supportedTypesCache.get(rawType);
if (result != null) {
return result;
}
result = rawType.isInterface() && AnnotationUtils.findAnnotation(rawType, ProjectedPayload.class) != null;
supportedTypesCache.put(rawType, result);
return result;
}
@Override
public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {
return false;
}
@Override
protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
try {
return projectionFactory.io().stream(inputMessage.getBody()).read(clazz);
} catch (RuntimeException o_O) {
Throwable cause = o_O.getCause();
if (SAXParseException.class.isInstance(cause)) {
throw new HttpMessageNotReadableException("Cannot read input message!", cause, inputMessage);
} else {
throw o_O;
}
}
}
@Override
protected void writeInternal(Object t, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {}
}