package solutions.digamma.damas.rs.serialization;

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.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.annotation.XmlRootElement;
import javax.xml.namespace.QName;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

/**
 * Non-JAXB-annotated message body writer.
 *
 * @author Ahmad Shahwan
 */
@Provider
@Produces(MediaType.APPLICATION_XML)
public class XmlMessageBodyWriter
        implements MessageBodyWriter<Object> {

    @Override
    public boolean isWriteable(
            Class<?> klass,
            Type type,
            Annotation[] annotations,
            MediaType mediaType) {
        return !klass.isAnnotationPresent(XmlRootElement.class);
    }

    @Override
    public long getSize(
            Object o,
            Class<?> klass,
            Type type,
            Annotation[] annotations,
            MediaType mediaType) {
        return -1;
    }

    @Override
    public void writeTo(
            Object o,
            Class<?> klass,
            Type type,
            Annotation[] annotations,
            MediaType mediaType,
            MultivaluedMap<String, Object> multivaluedMap,
            OutputStream outputStream)
            throws IOException, WebApplicationException {
        try {
            JAXBContext context = JAXBContext.newInstance(klass);
            Marshaller marshaller = context.createMarshaller();
            String name = klass.getSimpleName();
            JAXBElement<?> root = new JAXBElement(new QName(name), klass, o);

            marshaller.marshal(root, outputStream);
        } catch (JAXBException e) {
            throw new IOException("Error writing XML entity.", e);
        }
    }
}

@@ -584,24 +584,68 @@
 Annotation;%0A
+import java.lang.reflect.ParameterizedType;%0A
 import java.
@@ -1838,28 +1838,31 @@
 e = 
-klass.getSimple
+getRootElement
 Name(
+type
 );%0A 
@@ -1898,16 +1898,12 @@
 t = 
-new JAXB
+wrap
 Elem
@@ -1934,17 +1934,16 @@
 ss, o);%0A
-%0A
         
@@ -2085,24 +2085,24 @@
 tity.%22, e);%0A
-
         %7D%0A  
@@ -2104,11 +2104,575 @@
  %7D%0A    %7D
+%0A%0A    private static String getRootElementName(Type type) %7B%0A        while (type instanceof ParameterizedType) %7B%0A            type = ((ParameterizedType) type).getRawType();%0A        %7D%0A        if (type instanceof Class) %7B%0A            return ((Class) type).getSimpleName();%0A        %7D else %7B%0A            return type.getTypeName();%0A        %7D%0A    %7D%0A%0A    private static %3CT%3E JAXBElement%3CT%3E wrapElement(%0A            QName name,%0A            Class%3CT%3E klass,%0A            Object o) %7B%0A        T entity = klass.cast(o);%0A        return new JAXBElement%3C%3E(name, klass, entity);%0A    %7D
 %0A%7D%0A

Use declaration type name for XML root element.