use of com.zimbra.common.soap.Element.XMLElement in project zm-mailbox by Zimbra.
the class JaxbToJsonTest method kvpForGetDLRespWithOwner.
/**
* Ensuring that JAXB can handle having an owner in a list that is not an empty array when there are no owners
*/
@Test
public void kvpForGetDLRespWithOwner() throws Exception {
Element jsonElem = JSONElement.mFactory.createElement(QName.get(AccountConstants.E_GET_DISTRIBUTION_LIST_RESPONSE, AccountConstants.NAMESPACE_STR));
populateGetDlResp(jsonElem);
Element xmlElem = XMLElement.mFactory.createElement(QName.get(AccountConstants.E_GET_DISTRIBUTION_LIST_RESPONSE, AccountConstants.NAMESPACE_STR));
populateGetDlResp(xmlElem);
logDebug("XmlElement (for comparison) ---> prettyPrint\n%1$s", xmlElem.prettyPrint());
logDebug("JSONElement (for comparison) ---> prettyPrint\n%1$s", jsonElem.prettyPrint());
List<KeyValuePair> attrs = Lists.newArrayList();
attrs.add(new KeyValuePair("mail", "fun@example.test"));
attrs.add(new KeyValuePair("zimbraMailStatus", "enabled"));
DistributionListInfo dl = new DistributionListInfo("myId", "my name", null, attrs);
dl.setDynamic(true);
DistributionListGranteeInfo grantee = new DistributionListGranteeInfo(GranteeType.usr, "ownerId", "ownerName");
dl.addOwner(grantee);
GetDistributionListResponse jaxb = new GetDistributionListResponse(dl);
Element xmlJaxbElem = JaxbUtil.jaxbToElement(jaxb, XMLElement.mFactory);
Element jsonJaxbElem = JacksonUtil.jaxbToJSONElement(jaxb);
GetDistributionListResponse roundtripped = JaxbUtil.elementToJaxb(jsonJaxbElem, GetDistributionListResponse.class);
GetDistributionListResponse roundtrippedX = JaxbUtil.elementToJaxb(xmlJaxbElem, GetDistributionListResponse.class);
logDebug("JSONElement from JAXB ---> prettyPrint\n%1$s", jsonJaxbElem.prettyPrint());
logDebug("XMLElement from JAXB ---> prettyPrint\n%1$s", xmlJaxbElem.prettyPrint());
List<? extends KeyValuePair> kvps = roundtripped.getDl().getAttrList();
Assert.assertEquals("roundtripped kvps num", 2, kvps.size());
Assert.assertEquals("roundtripped owner num", 1, roundtripped.getDl().getOwners().size());
Assert.assertEquals("roundtrippedX owner num", 1, roundtrippedX.getDl().getOwners().size());
}
use of com.zimbra.common.soap.Element.XMLElement in project zm-mailbox by Zimbra.
the class JaxbToElementTest method ConvActionRequestJaxbSubclassHandlingTestDisabled.
/**
* Explore handling of Jaxb classes which specify an @XmlElement with
* a super class. How do subclasses get treated with this?
* WSDLJaxbTest.ConvActionRequestJaxbSubclassHandlingTest passes,
* i.e. it successfully unmarshalls to a ConvActionRequest with
* a FolderActionSelector member.
* However, even if I use those class files (with package name changed)
* in place of the committed ones, this test only seems to unmarshall
* with an ActionSelector member - i.e. the "recursive" and "url"
* attribute information gets lost.
*/
// @Test
public void ConvActionRequestJaxbSubclassHandlingTestDisabled() throws Exception {
ConvActionSelector actionSelector = ConvActionSelector.createForIdsAndOperation("ids", "op");
actionSelector.setAcctRelativePath("folder");
ConvActionRequest car = new ConvActionRequest(actionSelector);
Element carE = JaxbUtil.jaxbToElement(car);
String eXml = carE.toString();
ZimbraLog.test.debug("ConvActionRequestJaxbSubclassHandling: marshalled XML=%s", eXml);
Assert.assertTrue("Xml should contain acctRelPath attribute", eXml.contains("acctRelPath=\"folder\""));
carE = Element.XMLElement.mFactory.createElement(MailConstants.CONV_ACTION_REQUEST);
Element actionE = carE.addNonUniqueElement(MailConstants.E_ACTION);
actionE.addAttribute(MailConstants.A_OPERATION, "op");
actionE.addAttribute(MailConstants.A_ID, "ids");
actionE.addAttribute(MailConstants.A_ACCT_RELATIVE_PATH, "folder");
ZimbraLog.test.debug("ConvActionRequestJaxbSubclassHandling: half baked XML=%s", carE.toString());
car = JaxbUtil.elementToJaxb(carE);
carE = JaxbUtil.jaxbToElement(car);
eXml = carE.toString();
ZimbraLog.test.debug("ConvActionRequestJaxbSubclassHandling: round tripped XML=%s", eXml);
ConvActionSelector as = car.getAction();
Assert.assertEquals("acctRelPath attr value", "folder", as.getAcctRelativePath());
}
use of com.zimbra.common.soap.Element.XMLElement in project zm-mailbox by Zimbra.
the class JaxbUtil method fixupStructureForJaxb.
/**
* Manipulates a structure under {@link elem} which obeys Zimbra's SOAP XML structure rules to comply with more
* stringent JAXB rules.
* <ol>
* <li>Zimbra allows attributes to be specified as elements.
* <p>One scenario where this happens - {@link XMLElement}'s {@code getAttribute(String key, String defaultValue)}
* will look for an attribute with "key" as the name.
* If it fails to find that, it looks for an element with "key" as the name and returns the elements text.</p></li>
* <li>Zimbra allows elements to be specified as attributes.
* <p>One scenario where this happens.
* <pre>
* elem.addAttribute("xml-elem-json-attr", "XML elem but JSON attribute", Element.Disposition.CONTENT);
* </pre>
* Will be serialized to this JSON (i.e. treated as an attribute in JSON) :
* <pre>
* "xml-elem-json-attr": "XML elem but JSON attribute"
* </pre>
* or to this XML (i.e. treated as an element in XML) :
* <pre>
* <xml-elem-json-attr>XML elem but JSON attribute</xml-elem-json-attr>
* </pre>
* In JAXB, we typically use {@link XmlElement} for the associated field. Round tripping from XML will result in
* an element but round tripping from JSON will result in an attribute.
* <li>Zimbra uses key/value pairs which serialize to JSON as:
* <pre>
* "_attrs":{"anID":"val","anID2":"val2"}
* </pre>
* If this is read into a JSONElement structure and written out as XML, you get:
* <pre>
* <a n="anID">val</a><a n="anID2">val2</a>
* </pre>
* The element name "a" and the attribute name "n" are defaults - the actual expected values can be different - so
* we query the JAXB classes to see what they should be.
* </ol>
* @param klass is the JAXB class for {@code elem} which must be under the "com.zimbra" package hierarchy.
*/
private static void fixupStructureForJaxb(org.w3c.dom.Element elem, Class<?> klass) {
if (elem == null) {
return;
}
if (klass == null) {
LOG.debug("JAXB no class associated with " + elem.getLocalName());
return;
}
if (!isJaxbType(klass)) {
return;
}
JaxbInfo jaxbInfo = JaxbInfo.getFromCache(klass);
NamedNodeMap attrs = elem.getAttributes();
int numAttrs = attrs.getLength();
List<String> orphanAttrs = null;
// Process each attribute
for (int i = 0; i < numAttrs; i++) {
Attr attr = (Attr) attrs.item(i);
// Get attribute name and value
String attrName = attr.getNodeName();
if (!jaxbInfo.hasAttribute(attrName) && jaxbInfo.hasElement(attrName)) {
if (orphanAttrs == null) {
orphanAttrs = Lists.newArrayList();
}
orphanAttrs.add(attrName);
String attrValue = attr.getNodeValue();
elem.getNamespaceURI();
org.w3c.dom.Element newElem = elem.getOwnerDocument().createElementNS(elem.getNamespaceURI(), attrName);
newElem.setTextContent(attrValue);
elem.appendChild(newElem);
}
}
if (orphanAttrs != null) {
for (String orphan : orphanAttrs) {
attrs.removeNamedItem(orphan);
}
}
NodeList list = elem.getChildNodes();
List<org.w3c.dom.Element> orphans = null;
for (int i = 0; i < list.getLength(); i++) {
Node subnode = list.item(i);
if (subnode.getNodeType() == Node.ELEMENT_NODE) {
org.w3c.dom.Element child = (org.w3c.dom.Element) subnode;
String childName = child.getLocalName();
if (jaxbInfo.hasWrapperElement(childName)) {
NodeList wrappedList = child.getChildNodes();
for (int j = 0; j < wrappedList.getLength(); j++) {
Node wSubnode = wrappedList.item(j);
if (wSubnode.getNodeType() == Node.ELEMENT_NODE) {
org.w3c.dom.Element wChild = (org.w3c.dom.Element) wSubnode;
fixupStructureForJaxb(wChild, jaxbInfo.getClassForWrappedElement(childName, wChild.getLocalName()));
}
}
} else if (jaxbInfo.hasElement(childName)) {
fixupStructureForJaxb(child, jaxbInfo.getClassForElement(childName));
} else if (jaxbInfo.hasAttribute(childName)) {
elem.setAttribute(childName, child.getTextContent());
// Don't remove pre-existing child until later pass to avoid changing the list of child elements
if (orphans == null) {
orphans = Lists.newArrayList();
}
orphans.add(child);
} else if (Element.XMLElement.E_ATTRIBUTE.equals(childName)) {
// This might be a keyvaluepair, the Element code doesn't have access to JAXB info, so defaults
// the element name to "a" and its attribute will be "n". If this is what has happened, replace
// it with a corrected equivalent using the JAXB object for reference.
JaxbInfo.KeyValuePairXmlRepresentationInfo kvpXmlRep = jaxbInfo.getKeyValuePairElementInfo();
if (kvpXmlRep != null) {
elem.getNamespaceURI();
org.w3c.dom.Element newElem = elem.getOwnerDocument().createElementNS(elem.getNamespaceURI(), kvpXmlRep.getXmlElementName());
newElem.setTextContent(child.getTextContent());
newElem.setAttribute(kvpXmlRep.getXmlAttributeName(), child.getAttribute(Element.XMLElement.A_ATTR_NAME));
elem.appendChild(newElem);
if (orphans == null) {
orphans = Lists.newArrayList();
}
orphans.add(child);
}
} else {
LOG.debug("JAXB class " + klass.getName() + " does NOT recognise element named:" + childName);
}
}
}
// Prune the promoted elements from the list of children
if (orphans != null) {
for (org.w3c.dom.Element orphan : orphans) {
elem.removeChild(orphan);
}
}
}
use of com.zimbra.common.soap.Element.XMLElement in project zm-mailbox by Zimbra.
the class JaxbUtil method addChildElementFromJaxb.
public static Element addChildElementFromJaxb(Element parent, String name, String namespace, Object o) {
Element.ElementFactory factory;
if (parent instanceof XMLElement) {
factory = XMLElement.mFactory;
} else {
factory = JSONElement.mFactory;
}
Element child = null;
try {
child = jaxbToNamedElement(name, namespace, o, factory);
} catch (ServiceException e) {
ZimbraLog.misc.info("JAXB Problem making " + name + " element", e);
}
parent.addElement(child);
return child;
}
use of com.zimbra.common.soap.Element.XMLElement in project zm-mailbox by Zimbra.
the class JaxbToJsonTest method wrapperAbsentIfEmpty.
/**
* How to achieve a wrapped list where no element for the wrapper will appear in the XML if the list is empty.
* This no longer works! Fortunately, looks like we don't use any classes similar to WrapperAbsentIfEmpty
* at the moment.
* For JUDASPRIEST/Java 7 setNumbers is called with 2 integers. For main/Java 8
* it is called with an empty list.
* WrapperAbsentIfEmpty.setNumbers(List<Integer>) line: 51
* WrapperAbsentIfEmpty$JaxbAccessorM_getNumbers_setNumbers_java_util_List.set(Object, Object) line: 60
* Lister$CollectionLister<BeanT,T>.startPacking(BeanT, Accessor<BeanT,T>) line: 298
* Lister$CollectionLister<BeanT,T>.startPacking(Object, Accessor) line: 269
* Scope<BeanT,PropT,ItemT,PackT>.start(Accessor<BeanT,PropT>, Lister<BeanT,PropT,ItemT,PackT>) line: 142
* ArrayERProperty$ItemsLoader.startElement(UnmarshallingContext$State, TagName) line: 119
* UnmarshallingContext._startElement(TagName) line: 501
* UnmarshallingContext.startElement(TagName) line: 480
* InterningXmlVisitor.startElement(TagName) line: 75
* SAXConnector.startElement(String, String, String, Attributes) line: 150
* DOMScanner.visit(Element) line: 244
* DOMScanner.visit(Node) line: 281
* DOMScanner.visit(Element) line: 250
* DOMScanner.scan(Element) line: 127
* UnmarshallerImpl.unmarshal0(Node, JaxBeanInfo) line: 369
* UnmarshallerImpl.unmarshal(Node, Class<T>) line: 348
* JaxbUtil.rawW3cDomDocToJaxb(Document, Class<?>, boolean) line: 1420
* JaxbUtil.w3cDomDocToJaxb(Document, Class<?>, boolean) line: 1392
* JaxbUtil.elementToJaxb(Element, Class<?>) line: 1438
* JaxbToJsonTest.wrapperAbsentIfEmpty() line: 1516
*/
@Ignore("Bug:95509 - this is hypothetical functionality that isn't currently used, so low priority")
@Test
public void wrapperAbsentIfEmpty() throws Exception {
WrapperAbsentIfEmpty jaxb = new WrapperAbsentIfEmpty();
Element jsonJaxbElem = JacksonUtil.jaxbToJSONElement(jaxb);
WrapperAbsentIfEmpty roundtripped = JaxbUtil.elementToJaxb(jsonJaxbElem, WrapperAbsentIfEmpty.class);
logDebug("JSONElement from JAXB (empty numbers)--> prettyPrint\n%1$s", jsonJaxbElem.prettyPrint());
Assert.assertNull("original getNumbers (empty list)", jaxb.getNumbers());
Assert.assertNull("JSON roundtripped getNumbers (empty list)", roundtripped.getNumbers());
Assert.assertEquals("JSON for empty Numbers", "{\n \"_jsns\": \"urn:zimbraTest\"\n}", jsonJaxbElem.prettyPrint());
Element xmlElem = JaxbUtil.jaxbToElement(jaxb, Element.XMLElement.mFactory, true, false);
logDebug("XmlElement from JAXB (empty numbers) ---> prettyPrint\n%1$s", xmlElem.prettyPrint());
WrapperAbsentIfEmpty roundtrippedX = JaxbUtil.elementToJaxb(xmlElem, WrapperAbsentIfEmpty.class);
Assert.assertNull("XML roundtripped getNumbers (empty list)", roundtrippedX.getNumbers());
Assert.assertEquals("XML for empty Numbers", "<wrapper-absent-if-empty xmlns=\"urn:zimbraTest\"/>", xmlElem.prettyPrint());
jaxb.addNumber(314159);
jaxb.addNumber(42);
jsonJaxbElem = JacksonUtil.jaxbToJSONElement(jaxb);
roundtripped = JaxbUtil.elementToJaxb(jsonJaxbElem, WrapperAbsentIfEmpty.class);
logDebug("JSONElement from JAXB (empty numbers)--> prettyPrint\n%1$s", jsonJaxbElem.prettyPrint());
Assert.assertEquals("original size of Numbers (2 numbers)", 2, jaxb.getNumbers().size());
Assert.assertNotNull("XML roundtripped getNumbers (when 2 numbers in list)", roundtrippedX.getNumbers());
Assert.assertEquals("JSON roundtripped size of Numbers (2 numbers)", 2, roundtripped.getNumbers().size());
xmlElem = JaxbUtil.jaxbToElement(jaxb, Element.XMLElement.mFactory, true, false);
logDebug("XmlElement from JAXB (empty numbers) ---> prettyPrint\n%1$s", xmlElem.prettyPrint());
roundtrippedX = JaxbUtil.elementToJaxb(xmlElem, WrapperAbsentIfEmpty.class);
Assert.assertEquals("XML roundtripped size of Numbers (2 numbers)", 2, roundtrippedX.getNumbers().size());
Assert.assertEquals("XML when have 2 numbers", String.format("%s\n %s\n %s\n %s\n %s\n%s", "<wrapper-absent-if-empty xmlns=\"urn:zimbraTest\">", "<numbers>", "<number>314159</number>", "<number>42</number>", "</numbers>", "</wrapper-absent-if-empty>"), xmlElem.prettyPrint());
}
Aggregations