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); } } } }
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; }