Juan Hernandez has uploaded a new change for review. Change subject: restapi: JAXB provider ......................................................................
restapi: JAXB provider Currently we use a custom message body reader to parse XML input documents, and we use the default message body writer to generate XML documents. This patch converts the custom message body reader into a provider that acts as both reader and writer. This reduces the number of JAXB contexts created and will simplify removing some dependencies on Resteasy. Change-Id: I5208c9d41ab892f55c85ef095f25648f1a95d8df Signed-off-by: Juan Hernandez <[email protected]> --- R backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/xml/JAXBProvider.java M backend/manager/modules/restapi/interface/definition/src/main/resources/META-INF/services/javax.ws.rs.ext.Providers 2 files changed, 79 insertions(+), 7 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/89/29789/1 diff --git a/backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/xml/JAXBMessageBodyReader.java b/backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/xml/JAXBProvider.java similarity index 60% rename from backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/xml/JAXBMessageBodyReader.java rename to backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/xml/JAXBProvider.java index 922f401..376c47a 100644 --- a/backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/xml/JAXBMessageBodyReader.java +++ b/backend/manager/modules/restapi/interface/definition/src/main/java/org/ovirt/engine/api/xml/JAXBProvider.java @@ -18,17 +18,23 @@ import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.lang.reflect.Type; import javax.ws.rs.Consumes; +import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.MessageBodyReader; +import javax.ws.rs.ext.MessageBodyWriter; import javax.ws.rs.ext.Provider; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.bind.ValidationEventHandler; import javax.xml.stream.XMLInputFactory; @@ -36,20 +42,28 @@ import javax.xml.stream.XMLStreamReader; import org.ovirt.engine.api.model.API; +import org.ovirt.engine.api.model.ObjectFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * This class is responsible for converting XML documents into model objects. Note that it can't be a generic class - * because if it is then the JAX-RS framework will select other builtin classes that are more specific. + * This class is responsible for converting XML documents into model objects, and the other way around. Note that it + * can't be a generic class because if it is then the JAX-RS framework will select other builtin classes that are more + * specific. */ @Provider @Consumes(MediaType.APPLICATION_XML) -public class JAXBMessageBodyReader implements MessageBodyReader<Object> { +@Produces(MediaType.APPLICATION_XML) +public class JAXBProvider implements MessageBodyReader<Object>, MessageBodyWriter<Object> { /** * The logger used by this class. */ - private Logger log = LoggerFactory.getLogger(JAXBMessageBodyReader.class); + private Logger log = LoggerFactory.getLogger(JAXBProvider.class); + + /** + * The factory used to create JAXB elements. + */ + private ObjectFactory objectFactory; /** * The factory used to create XML document readers. @@ -66,7 +80,10 @@ */ private ValidationEventHandler jaxbHandler = new JAXBValidationEventHandler(); - public JAXBMessageBodyReader() { + public JAXBProvider() { + // Create the object factory: + objectFactory = new ObjectFactory(); + // Create a factory that will produce XML parsers that ignore entity references and DTDs: parserFactory = XMLInputFactory.newFactory(); parserFactory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false); @@ -87,8 +104,24 @@ * {@inheritDoc} */ @Override - public boolean isReadable(Class<?> type, Type genericType, Annotation annotations[], MediaType mediaType) { + public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return true; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public long getSize(Object o, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return -1; } /** @@ -144,4 +177,43 @@ throw new IOException(exception); } } + + @Override + public void writeTo(Object object, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) + throws IOException, WebApplicationException { + // In order to create the JAXB element that wraps the object we need to iterate the object factory and find the + // method that creates it: + Method factoryMethod = null; + for (Method currentMethod : ObjectFactory.class.getDeclaredMethods()) { + Class<?>[] parameterTypes = currentMethod.getParameterTypes(); + if (parameterTypes.length == 1 && parameterTypes[0] == type) { + factoryMethod = currentMethod; + break; + } + } + if (factoryMethod == null) { + throw new IOException("Can't find factory method for type \"" + type.getName() + "\"."); + } + + // Invoke the method to create the JAXB element: + JAXBElement<Object> element; + try { + element = (JAXBElement<Object>) factoryMethod.invoke(objectFactory, object); + } + catch (IllegalAccessException|InvocationTargetException exception) { + throw new IOException("Error invoking factory method for type \"" + type.getName() + "\".", exception); + } + + // Marshal the element: + try { + Marshaller marshaller = jaxbContext.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); + marshaller.marshal(element, entityStream); + } + catch (JAXBException exception) { + throw new IOException("Can't marshall JAXB element of type \"" + type.getName() + "\".", exception); + } + } } diff --git a/backend/manager/modules/restapi/interface/definition/src/main/resources/META-INF/services/javax.ws.rs.ext.Providers b/backend/manager/modules/restapi/interface/definition/src/main/resources/META-INF/services/javax.ws.rs.ext.Providers index 68c4f63..27d3917 100644 --- a/backend/manager/modules/restapi/interface/definition/src/main/resources/META-INF/services/javax.ws.rs.ext.Providers +++ b/backend/manager/modules/restapi/interface/definition/src/main/resources/META-INF/services/javax.ws.rs.ext.Providers @@ -1,3 +1,3 @@ org.ovirt.engine.api.resteasy.json.JsonProvider -org.ovirt.engine.api.xml.JAXBMessageBodyReader +org.ovirt.engine.api.xml.JAXBProvider org.ovirt.engine.api.pdf.FOPMessageBodyWriter -- To view, visit http://gerrit.ovirt.org/29789 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I5208c9d41ab892f55c85ef095f25648f1a95d8df Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Juan Hernandez <[email protected]> _______________________________________________ Engine-patches mailing list [email protected] http://lists.ovirt.org/mailman/listinfo/engine-patches
