content: package com.github.aesteve.vertx.nubes.marshallers.impl;
  
  import com.github.aesteve.vertx.nubes.exceptions.MarshallingException;
  import com.github.aesteve.vertx.nubes.marshallers.PayloadMarshaller;
  import com.github.aesteve.vertx.nubes.utils.StackTracePrinter;
  import io.vertx.core.VertxException;
  import org.w3c.dom.Document;
  import org.xml.sax.InputSource;
  import org.xml.sax.SAXException;
  
  import javax.xml.bind.JAXBContext;
  import javax.xml.bind.JAXBException;
  import javax.xml.bind.Marshaller;
  import javax.xml.bind.Unmarshaller;
  import javax.xml.parsers.DocumentBuilder;
  import javax.xml.parsers.DocumentBuilderFactory;
  import javax.xml.parsers.ParserConfigurationException;
  import java.io.IOException;
  import java.io.StringReader;
  import java.io.StringWriter;
  import java.util.Set;
  
  import static com.github.aesteve.vertx.nubes.marshallers.PayloadMarshaller.Constants.ERROR_CODE_KEY;
  import static com.github.aesteve.vertx.nubes.marshallers.PayloadMarshaller.Constants.ERROR_KEY;
  import static com.github.aesteve.vertx.nubes.marshallers.PayloadMarshaller.Constants.ERROR_MESSAGE_KEY;
  
  public class JAXBPayloadMarshaller implements PayloadMarshaller {
  
    protected Marshaller marshaller;
    protected Unmarshaller unmarshaller;
  
    public JAXBPayloadMarshaller(Set<Class<?>> classes) throws JAXBException {
      JAXBContext jc = JAXBContext.newInstance(classes.toArray(new Class<?>[0]));
      marshaller = jc.createMarshaller();
      unmarshaller = jc.createUnmarshaller();
    }
  
    @Override
    public <T> T unmarshallPayload(String body, Class<T> clazz) {
      try {
        return unmarshaller.unmarshal(loadXMLFromString(body), clazz).getValue();
      } catch (MarshallingException | JAXBException e) {
        throw new VertxException(e);
      }
    }
  
    @Override
    public String marshallPayload(Object payload) {
      StringWriter writer = new StringWriter();
      try {
        marshaller.marshal(payload, writer);
      } catch (JAXBException je) {
        throw new VertxException(je);
      }
      return writer.toString();
    }
  
    public static Document loadXMLFromString(String xml) throws MarshallingException {
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      DocumentBuilder builder;
      try {
        builder = factory.newDocumentBuilder();
      } catch (ParserConfigurationException e) {
        throw new MarshallingException(e);
      }
      try (StringReader reader = new StringReader(xml)){
        return builder.parse(new InputSource(reader));
      } catch (SAXException | IOException e) {
        throw new MarshallingException(e);
      }
    }
  
    @Override
    public String marshallUnexpectedError(Throwable error, boolean displayDetails) {
      return marshallError(500, error, null);
    }
  
    @Override
    public String marshallHttpStatus(int statusCode, String errorMessage) {
      return marshallError(statusCode, null, errorMessage);
    }
  
    private static String marshallError(int status, Throwable error, String message) {
      String errorMsg = message;
      if (message == null && error != null) {
        errorMsg = StackTracePrinter.asLineString(new StringBuilder(), error).toString();
      }
      return "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" + "<" + ERROR_KEY + ">\n" +
          "\t<" + ERROR_CODE_KEY + ">" + status + "</" + ERROR_CODE_KEY + ">\n" +
          "\t<" + ERROR_MESSAGE_KEY + ">\n<![CDATA[" +
          errorMsg +
          "]]>\n\t</" + ERROR_MESSAGE_KEY + ">\n" +
          "</" + ERROR_KEY + ">";
    }
  }
  