use of com.zimbra.common.soap.Element.JSONElement in project zm-mailbox by Zimbra.
the class JaxbToJsonTest method missingRequiredStringElem.
/**
* Permissive handling - if required things are not present, users need to handle this
*/
@Test
public void missingRequiredStringElem() throws Exception {
final String attr1Val = "My attribute ONE";
StringAttrStringElem tstr = new StringAttrStringElem();
tstr.setAttr1(attr1Val);
// tstr.setElem1(elem1Val);
Element jsonJaxbElem = JacksonUtil.jaxbToJSONElement(tstr);
logDebug("JSONElement from JAXB ---> prettyPrint\n%1$s", jsonJaxbElem.prettyPrint());
StringAttrStringElem roundtripped = JaxbUtil.elementToJaxb(jsonJaxbElem, StringAttrStringElem.class);
Assert.assertEquals("JSONElement attr1", attr1Val, jsonJaxbElem.getAttribute("attribute-1"));
try {
jsonJaxbElem.getElement("element1");
} catch (ServiceException svcE) {
Assert.assertEquals("JSONElement exception when getting missing item:", ServiceException.INVALID_REQUEST, svcE.getCode());
}
Assert.assertEquals("roundtripped attr1", attr1Val, roundtripped.getAttr1());
Assert.assertEquals("roundtripped elem1", null, roundtripped.getElem1());
}
use of com.zimbra.common.soap.Element.JSONElement in project zm-mailbox by Zimbra.
the class JaxbToJsonTest method xmlValueAnnotation.
/**
* XmlValue should map to an attribute with name "_content"
* At present, classes that want this feature need the annotation @JsonProperty("_content"),
* otherwise, the name "value" is used.
* "chunk": [ { "disp": "disposition 1", "_content": "text 1\nIn the sun" },
* { "disp": "disPosition 2", "_content": "text 2" }],
*/
@Test
public void xmlValueAnnotation() throws Exception {
String dispos1 = "disposition 1";
String text1 = "text 1\nIn the sun";
String dispos2 = "disPosition 2";
String text2 = "text 2";
// --------------------------------- For Comparison - Element handling where the JAXB has an @XmlValue
Element legacyElem = JSONElement.mFactory.createElement(MailConstants.DIFF_DOCUMENT_RESPONSE);
legacyElem.addNonUniqueElement(MailConstants.E_CHUNK).addAttribute(MailConstants.A_DISP, dispos1).setText(text1);
legacyElem.addNonUniqueElement(MailConstants.E_CHUNK).addAttribute(MailConstants.A_DISP, dispos2).setText(text2);
logDebug("DiffDocumentResponse JSONElement ---> prettyPrint\n%1$s", legacyElem.prettyPrint());
// --------------------------------- @XmlValue handling test - need @JsonProperty("_content") annotation
DiffDocumentResponse ddResp = new DiffDocumentResponse();
ddResp.addChunk(DispositionAndText.create(dispos1, text1));
ddResp.addChunk(DispositionAndText.create(dispos2, text2));
Element jsonJaxbElem = JacksonUtil.jaxbToJSONElement(ddResp);
logDebug("DiffDocumentResponse JSONElement from JAXB ---> prettyPrint\n%1$s", jsonJaxbElem.prettyPrint());
List<Element> chunks = jsonJaxbElem.listElements();
Assert.assertEquals("Number of child elements", 2, chunks.size());
Element chunk1 = chunks.get(0);
Element chunk2 = chunks.get(1);
Assert.assertEquals("1st chunk disposition", dispos1, chunk1.getAttribute(MailConstants.A_DISP));
Assert.assertEquals("1st chunk value", text1, chunk1.getText());
Assert.assertEquals("2nd chunk disposition", dispos2, chunk2.getAttribute(MailConstants.A_DISP));
Assert.assertEquals("2nd chunk value", text2, chunk2.getText());
DiffDocumentResponse roundtripped = JaxbUtil.elementToJaxb(jsonJaxbElem, DiffDocumentResponse.class);
List<DispositionAndText> rtChunks = roundtripped.getChunks();
Assert.assertEquals("Number of roundtripped chunks", 2, rtChunks.size());
DispositionAndText rtChunk1 = rtChunks.get(0);
DispositionAndText rtChunk2 = rtChunks.get(1);
Assert.assertEquals("1st roundtripped chunk disposition", dispos1, rtChunk1.getDisposition());
Assert.assertEquals("1st roundtripped chunk value", text1, rtChunk1.getText());
Assert.assertEquals("2nd roundtripped chunk disposition", dispos2, rtChunk2.getDisposition());
Assert.assertEquals("2nd roundtripped chunk value", text2, rtChunk2.getText());
}
use of com.zimbra.common.soap.Element.JSONElement in project zm-mailbox by Zimbra.
the class JaxbToJsonTest method zimbraKeyValuePairsAnnotation.
/**
* Check that JSON can be deserialised into a JAXB object when some of the JSON represents Zimbra KeyValuePairs
* (i.e. An "_attrs" array).
* In this case, the target objects for each keyvalue pair use the defaults of "a" for the element name and
* "n" for the attribute name in the XML form.
* Desired XML :<br />
* <key-value-pairs-tester xmlns="urn:zimbraTest">
* <a n="key1">value1</a>
* <a n="key2">value2-a</a>
* <a n="key2">value2-b</a>
* </key-value-pairs-tester>
*<br />
* Desired JSON :<br />
* {
* "_attrs": {
* "key1": "value1",
* "key2": [
* "value2-a",
* "value2-b"]
* },
* "_jsns": "urn:zimbraTest"
* }
*/
@Test
public void zimbraKeyValuePairsAnnotation() throws Exception {
Element jsonElem = JSONElement.mFactory.createElement(QName.get("key-value-pairs", "urn:zimbraTest"));
jsonElem.addKeyValuePair("key1", "value1");
jsonElem.addKeyValuePair("key2", "value2-a");
jsonElem.addKeyValuePair("key2", "value2-b");
List<KeyValuePair> attrs = Lists.newArrayList();
attrs.add(new KeyValuePair("key1", "value1"));
attrs.add(new KeyValuePair("key2", "value2-a"));
attrs.add(new KeyValuePair("key2", "value2-b"));
KeyValuePairsTester jaxb = new KeyValuePairsTester(attrs);
logDebug("XMLElement (from JAXB) ---> prettyPrint\n%1$s", JaxbUtil.jaxbToElement(jaxb, Element.XMLElement.mFactory, true, false).prettyPrint());
Element jsonJaxbElem = JacksonUtil.jaxbToJSONElement(jaxb);
logDebug("JSONElement (for comparison) ---> prettyPrint\n%1$s", jsonElem.prettyPrint());
logDebug("JSONElement from JAXB ---> prettyPrint\n%1$s", jsonJaxbElem.prettyPrint());
KeyValuePairsTester roundtripped = JaxbUtil.elementToJaxb(jsonJaxbElem, KeyValuePairsTester.class);
List<Element.KeyValuePair> elemKVPs = jsonJaxbElem.listKeyValuePairs();
Assert.assertEquals("elemKVP num", 3, elemKVPs.size());
Assert.assertEquals("prettyPrint", jsonElem.prettyPrint(), jsonJaxbElem.prettyPrint());
List<KeyValuePair> kvps = roundtripped.getAttrList();
Assert.assertEquals("roundtripped kvps num", 3, kvps.size());
}
use of com.zimbra.common.soap.Element.JSONElement 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.JSONElement 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);
}
}
}
Aggregations