private static <T> T getParamXPath(
     final Class<T> pClass, final String pXpath, final CompactFragment pBody) throws XmlException {
   // TODO Avoid JAXB where possible, use XMLDeserializer instead
   final boolean string = CharSequence.class.isAssignableFrom(pClass);
   Node match;
   DocumentFragment fragment =
       DomUtil.childrenToDocumentFragment(XMLFragmentStreamReader.from(pBody));
   for (Node n = fragment.getFirstChild(); n != null; n = n.getNextSibling()) {
     match = xpathMatch(n, pXpath);
     if (match != null) {
       if (!string) {
         XmlDeserializer deserializer = pClass.getAnnotation(XmlDeserializer.class);
         if (deserializer != null) {
           try {
             XmlDeserializerFactory<?> factory = deserializer.value().newInstance();
             factory.deserialize(XmlStreaming.newReader(new DOMSource(n)));
           } catch (InstantiationException | IllegalAccessException e) {
             throw new RuntimeException(e);
           }
         } else {
           return JAXB.unmarshal(new DOMSource(match), pClass);
         }
       } else {
         return pClass.cast(nodeToString(match));
       }
     }
   }
   return null;
 }
  private void serializeValue(final HttpServletResponse pResponse, Object value)
      throws TransformerException, IOException, FactoryConfigurationError {
    if (value instanceof Source) {
      setContentType(pResponse, "application/binary"); // Unknown content type
      Sources.writeToStream((Source) value, pResponse.getOutputStream());
    } else if (value instanceof Node) {
      pResponse.setContentType("text/xml");
      Sources.writeToStream(new DOMSource((Node) value), pResponse.getOutputStream());
    } else if (value instanceof XmlSerializable) {
      pResponse.setContentType("text/xml");
      XMLOutputFactory factory = XMLOutputFactory.newInstance();
      factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, Boolean.TRUE);
      try {
        XmlWriter out =
            XmlStreaming.newWriter(
                pResponse.getOutputStream(), pResponse.getCharacterEncoding(), true);
        try {
          out.startDocument(null, null, null);
          ((XmlSerializable) value).serialize(out);
          out.endDocument();
        } finally {
          out.close();
        }
      } catch (XmlException e) {
        throw new TransformerException(e);
      }
    } else if (value instanceof Collection) {
      final XmlElementWrapper annotation = getElementWrapper();
      if (annotation != null) {
        setContentType(pResponse, "text/xml");
        try (OutputStream outStream = pResponse.getOutputStream()) {

          writeCollection(
              outStream, getGenericReturnType(), (Collection<?>) value, getQName(annotation));
        }
      }
    } else if (value instanceof CharSequence) {
      setContentType(pResponse, "text/plain");
      pResponse.getWriter().append((CharSequence) value);
    } else {
      if (value != null) {
        try {
          final JAXBContext jaxbContext = JAXBContext.newInstance(getReturnType());
          setContentType(pResponse, "text/xml");

          final JAXBSource jaxbSource = new JAXBSource(jaxbContext, value);
          Sources.writeToStream(jaxbSource, pResponse.getOutputStream());

        } catch (final JAXBException e) {
          throw new MessagingException(e);
        }
      }
    }
  }
  @NotNull
  @Override
  public SimpleAdapter marshal(@NotNull final XmlSerializable v) throws Exception {

    final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setNamespaceAware(true);
    final Document document = dbf.newDocumentBuilder().newDocument();
    final DocumentFragment content = document.createDocumentFragment();
    final XMLOutputFactory xof = XMLOutputFactory.newFactory();
    final XMLStreamWriter out = xof.createXMLStreamWriter(new DOMResult(content));

    v.serialize(XmlStreaming.newWriter(new DOMResult(content)));
    final int childCount = content.getChildNodes().getLength();
    if (childCount == 0) {
      return new SimpleAdapter();
    } else if (childCount == 1) {
      final SimpleAdapter result = new SimpleAdapter();
      final Node child = content.getFirstChild();
      if (child instanceof Element) {
        result.setAttributes(child.getAttributes());
        for (Node child2 = child.getFirstChild();
            child2 != null;
            child2 = child2.getNextSibling()) {
          result.children.add(child2);
        }
      } else {
        result.children.add(child);
      }
      return result;
    } else { // More than one child
      final SimpleAdapter result = new SimpleAdapter();
      for (Node child = content.getFirstChild(); child != null; child = child.getNextSibling()) {
        result.children.add(child);
      }
      return result;
    }
  }
 private void writeCollection(
     final OutputStream outputStream,
     final Type collectionType,
     final Collection<?> collection,
     final QName outerTagName) {
   final Class<?> rawType;
   if (collectionType instanceof ParameterizedType) {
     final ParameterizedType returnType = (ParameterizedType) collectionType;
     rawType = (Class<?>) returnType.getRawType();
   } else if (collectionType instanceof Class<?>) {
     rawType = (Class<?>) collectionType;
   } else if (collectionType instanceof WildcardType) {
     final Type[] UpperBounds = ((WildcardType) collectionType).getUpperBounds();
     if (UpperBounds.length > 0) {
       rawType = (Class<?>) UpperBounds[0];
     } else {
       rawType = Object.class;
     }
   } else if (collectionType instanceof TypeVariable) {
     final Type[] UpperBounds = ((TypeVariable<?>) collectionType).getBounds();
     if (UpperBounds.length > 0) {
       rawType = (Class<?>) UpperBounds[0];
     } else {
       rawType = Object.class;
     }
   } else {
     throw new IllegalArgumentException("Unsupported type variable");
   }
   Class<?> elementType;
   if (Collection.class.isAssignableFrom(rawType)) {
     final Type[] paramTypes = Types.getTypeParametersFor(Collection.class, collectionType);
     elementType = Types.toRawType(paramTypes[0]);
     if (elementType.isInterface()) {
       // interfaces not supported by jaxb
       elementType = Types.commonAncestor(collection);
     }
   } else {
     elementType = Types.commonAncestor(collection);
   }
   try {
     // As long as JAXB is an option, we have to know that this is a StAXWriter as JAXB needs to
     // write to that.
     try (XmlWriter xmlWriter = XmlStreaming.newWriter(outputStream, "UTF-8")) {
       Marshaller marshaller = null;
       XmlWriterUtil.smartStartTag(xmlWriter, outerTagName);
       for (Object item : collection) {
         if (item != null) {
           if (item instanceof XmlSerializable) {
             ((XmlSerializable) item).serialize(xmlWriter);
           } else if (item instanceof Node) {
             XmlWriterUtil.serialize(xmlWriter, (Node) item);
           } else {
             if (marshaller == null) {
               JAXBContext jaxbcontext = null;
               if (elementType == null) {
                 jaxbcontext = newJAXBContext(JAXBCollectionWrapper.class);
               } else {
                 jaxbcontext = newJAXBContext(JAXBCollectionWrapper.class, elementType);
               }
               marshaller = jaxbcontext.createMarshaller();
             }
             marshaller.marshal(item, (XMLStreamWriter) getDelegateMethod().invoke(xmlWriter));
           }
         }
       }
       XmlWriterUtil.endTag(xmlWriter, outerTagName);
     }
   } catch (Throwable e) {
     throw new MessagingException(e);
   }
 }
  private Object getParam(
      final Class<?> pClass,
      final String pName,
      final ParamType pType,
      final String pXpath,
      final HttpMessage pMessage)
      throws XmlException {
    Object result = null;
    switch (pType) {
      case GET:
        result = getParamGet(pName, pMessage);
        break;
      case POST:
        result = getParamPost(pName, pMessage);
        break;
      case QUERY:
        result = getParamGet(pName, pMessage);
        if (result == null) {
          result = getParamPost(pName, pMessage);
        }
        break;
      case VAR:
        result = mPathParams.get(pName);
        break;
      case XPATH:
        result = getParamXPath(pClass, pXpath, pMessage.getBody());
        break;
      case BODY:
        result = getBody(pClass, pMessage);
        break;
      case ATTACHMENT:
        result = getAttachment(pClass, pName, pMessage);
        break;
      case PRINCIPAL:
        {
          final Principal principal = pMessage.getUserPrincipal();
          if (pClass.isAssignableFrom(String.class)) {
            result = principal.getName();
          } else {
            result = principal;
          }
          break;
        }
    }
    // XXX generizice this and share the same approach to unmarshalling in ALL code
    // TODO support collection/list parameters
    if ((result != null) && (!pClass.isInstance(result))) {
      if ((Types.isPrimitive(pClass) || (Types.isPrimitiveWrapper(pClass)))
          && (result instanceof String)) {
        try {
          result = Types.parsePrimitive(pClass, ((String) result));
        } catch (NumberFormatException e) {
          throw new HttpResponseException(
              HttpServletResponse.SC_BAD_REQUEST, "The argument given is invalid", e);
        }
      } else if (Enum.class.isAssignableFrom(pClass)) {
        @SuppressWarnings({"rawtypes"})
        final Class clazz = pClass;
        @SuppressWarnings("unchecked")
        final Enum<?> tmpResult = Enum.valueOf(clazz, result.toString());
        result = tmpResult;
      } else if (result instanceof Node) {
        XmlDeserializer factory = pClass.getAnnotation(XmlDeserializer.class);
        if (factory != null) {
          try {
            result =
                factory
                    .value()
                    .newInstance()
                    .deserialize(XmlStreaming.newReader(new DOMSource((Node) result)));
          } catch (IllegalAccessException | InstantiationException e) {
            throw new XmlException(e);
          }
        } else {
          result = JAXB.unmarshal(new DOMSource((Node) result), pClass);
        }
      } else {
        final String s = result.toString();
        // Only wrap when we don't start with <
        final char[] requestBody =
            (s.startsWith("<") ? s : "<wrapper>" + s + "</wrapper>").toCharArray();
        if (requestBody.length > 0) {
          result = JAXB.unmarshal(new CharArrayReader(requestBody), pClass);
        } else {
          result = null;
        }
      }
    }

    return result;
  }