/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.camel.model.dataformat; import java.util.Arrays; import java.util.List; import java.util.Map; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlList; import javax.xml.bind.annotation.XmlRootElement; import org.apache.camel.CamelContext; import org.apache.camel.model.DataFormatDefinition; import org.apache.camel.spi.DataFormat; import org.apache.camel.spi.Metadata; /** * XML-JSon data format * * @version */ @Metadata(firstVersion = "2.10.0", label = "dataformat,transformation,xml,json", title = "XML JSon") @XmlRootElement(name = "xmljson") @XmlAccessorType(XmlAccessType.FIELD) public class XmlJsonDataFormat extends DataFormatDefinition { public static final String TYPE_HINTS = "typeHints"; public static final String REMOVE_NAMESPACE_PREFIXES = "removeNamespacePrefixes"; public static final String SKIP_NAMESPACES = "skipNamespaces"; public static final String TRIM_SPACES = "trimSpaces"; public static final String SKIP_WHITESPACE = "skipWhitespace"; public static final String EXPANDABLE_PROPERTIES = "expandableProperties"; public static final String ARRAY_NAME = "arrayName"; public static final String ELEMENT_NAME = "elementName"; public static final String ROOT_NAME = "rootName"; public static final String NAMESPACE_LENIENT = "namespaceLenient"; public static final String FORCE_TOP_LEVEL_OBJECT = "forceTopLevelObject"; public static final String ENCODING = "encoding"; @XmlAttribute private String encoding; @XmlAttribute private String elementName; @XmlAttribute private String arrayName; @XmlAttribute private Boolean forceTopLevelObject; @XmlAttribute private Boolean namespaceLenient; @XmlAttribute private String rootName; @XmlAttribute private Boolean skipWhitespace; @XmlAttribute private Boolean trimSpaces; @XmlAttribute private Boolean skipNamespaces; @XmlAttribute private Boolean removeNamespacePrefixes; @XmlAttribute @XmlList private List<String> expandableProperties; @XmlAttribute private String typeHints; public XmlJsonDataFormat() { super("xmljson"); } public XmlJsonDataFormat(Map<String, String> options) { super("xmljson"); if (options.containsKey(ENCODING)) { encoding = options.get(ENCODING); } if (options.containsKey(FORCE_TOP_LEVEL_OBJECT)) { forceTopLevelObject = Boolean.parseBoolean(options.get(FORCE_TOP_LEVEL_OBJECT)); } if (options.containsKey(NAMESPACE_LENIENT)) { namespaceLenient = Boolean.parseBoolean(options.get(NAMESPACE_LENIENT)); } if (options.containsKey(ROOT_NAME)) { rootName = options.get(ROOT_NAME); } if (options.containsKey(ELEMENT_NAME)) { elementName = options.get(ELEMENT_NAME); } if (options.containsKey(ARRAY_NAME)) { arrayName = options.get(ARRAY_NAME); } if (options.containsKey(EXPANDABLE_PROPERTIES)) { expandableProperties = Arrays.asList(options.get(EXPANDABLE_PROPERTIES).split(" ")); } if (options.containsKey(SKIP_WHITESPACE)) { skipWhitespace = Boolean.parseBoolean(options.get(SKIP_WHITESPACE)); } if (options.containsKey(TRIM_SPACES)) { trimSpaces = Boolean.parseBoolean(options.get(TRIM_SPACES)); } if (options.containsKey(SKIP_NAMESPACES)) { skipNamespaces = Boolean.parseBoolean(options.get(SKIP_NAMESPACES)); } if (options.containsKey(REMOVE_NAMESPACE_PREFIXES)) { removeNamespacePrefixes = Boolean.parseBoolean(options.get(REMOVE_NAMESPACE_PREFIXES)); } if (options.containsKey(TYPE_HINTS)) { typeHints = options.get(TYPE_HINTS); } } @Override protected void configureDataFormat(DataFormat dataFormat, CamelContext camelContext) { if (encoding != null) { setProperty(camelContext, dataFormat, ENCODING, encoding); } if (forceTopLevelObject != null) { setProperty(camelContext, dataFormat, FORCE_TOP_LEVEL_OBJECT, forceTopLevelObject); } if (namespaceLenient != null) { setProperty(camelContext, dataFormat, NAMESPACE_LENIENT, namespaceLenient); } if (rootName != null) { setProperty(camelContext, dataFormat, ROOT_NAME, rootName); } if (elementName != null) { setProperty(camelContext, dataFormat, ELEMENT_NAME, elementName); } if (arrayName != null) { setProperty(camelContext, dataFormat, ARRAY_NAME, arrayName); } if (expandableProperties != null && expandableProperties.size() != 0) { setProperty(camelContext, dataFormat, EXPANDABLE_PROPERTIES, expandableProperties); } if (skipWhitespace != null) { setProperty(camelContext, dataFormat, SKIP_WHITESPACE, skipWhitespace); } if (trimSpaces != null) { setProperty(camelContext, dataFormat, TRIM_SPACES, trimSpaces); } if (skipNamespaces != null) { setProperty(camelContext, dataFormat, SKIP_NAMESPACES, skipNamespaces); } if (removeNamespacePrefixes != null) { setProperty(camelContext, dataFormat, REMOVE_NAMESPACE_PREFIXES, removeNamespacePrefixes); } // will end up calling the setTypeHints(String s) which does the parsing from the Enum String key to the Enum value if (typeHints != null) { setProperty(camelContext, dataFormat, TYPE_HINTS, typeHints); } //TODO: xmljson: element-namespace mapping is not implemented in the XML DSL // depending on adoption rate of this data format, we'll make this data format NamespaceAware so that it gets // the prefix-namespaceURI mappings from the context, and with a new attribute called "namespacedElements", // we'll associate named elements with prefixes following a format "element1:prefix1,element2:prefix2,..." } public String getEncoding() { return encoding; } /** * Sets the encoding. * Used for unmarshalling (JSON to XML conversion). */ public void setEncoding(String encoding) { this.encoding = encoding; } public String getElementName() { return elementName; } /** * Specifies the name of the XML elements representing each array element. * Used for unmarshalling (JSON to XML conversion). */ public void setElementName(String elementName) { this.elementName = elementName; } public String getArrayName() { return arrayName; } /** * Specifies the name of the top-level XML element. * Used for unmarshalling (JSON to XML conversion). * * For example, when converting [1, 2, 3], it will be output by default as <a><e>1</e><e>2</e><e>3</e></a>. * By setting this option or rootName, you can alter the name of element 'a'. */ public void setArrayName(String arrayName) { this.arrayName = arrayName; } public Boolean getForceTopLevelObject() { return forceTopLevelObject; } /** * Determines whether the resulting JSON will start off with a top-most element whose name matches the XML root element. * Used for marshalling (XML to JSon conversion). * * If disabled, XML string <a><x>1</x><y>2</y></a> turns into { 'x: '1', 'y': '2' }. * Otherwise, it turns into { 'a': { 'x: '1', 'y': '2' }}. */ public void setForceTopLevelObject(Boolean forceTopLevelObject) { this.forceTopLevelObject = forceTopLevelObject; } public Boolean getNamespaceLenient() { return namespaceLenient; } /** * Flag to be tolerant to incomplete namespace prefixes. * Used for unmarshalling (JSON to XML conversion). * In most cases, json-lib automatically changes this flag at runtime to match the processing. */ public void setNamespaceLenient(Boolean namespaceLenient) { this.namespaceLenient = namespaceLenient; } public String getRootName() { return rootName; } /** * Specifies the name of the top-level element. * Used for unmarshalling (JSON to XML conversion). * * If not set, json-lib will use arrayName or objectName (default value: 'o', at the current time it is not configurable in this data format). * If set to 'root', the JSON string { 'x': 'value1', 'y' : 'value2' } would turn * into <root><x>value1</x><y>value2</y></root>, otherwise the 'root' element would be named 'o'. */ public void setRootName(String rootName) { this.rootName = rootName; } public Boolean getSkipWhitespace() { return skipWhitespace; } /** * Determines whether white spaces between XML elements will be regarded as text values or disregarded. * Used for marshalling (XML to JSon conversion). */ public void setSkipWhitespace(Boolean skipWhitespace) { this.skipWhitespace = skipWhitespace; } public Boolean getTrimSpaces() { return trimSpaces; } /** * Determines whether leading and trailing white spaces will be omitted from String values. * Used for marshalling (XML to JSon conversion). */ public void setTrimSpaces(Boolean trimSpaces) { this.trimSpaces = trimSpaces; } public Boolean getSkipNamespaces() { return skipNamespaces; } /** * Signals whether namespaces should be ignored. By default they will be added to the JSON output using @xmlns elements. * Used for marshalling (XML to JSon conversion). */ public void setSkipNamespaces(Boolean skipNamespaces) { this.skipNamespaces = skipNamespaces; } public Boolean getRemoveNamespacePrefixes() { return removeNamespacePrefixes; } /** * Removes the namespace prefixes from XML qualified elements, so that the resulting JSON string does not contain them. * Used for marshalling (XML to JSon conversion). */ public void setRemoveNamespacePrefixes(Boolean removeNamespacePrefixes) { this.removeNamespacePrefixes = removeNamespacePrefixes; } public List<String> getExpandableProperties() { return expandableProperties; } /** * With expandable properties, JSON array elements are converted to XML as a sequence of repetitive XML elements * with the local name equal to the JSON key, for example: { number: 1,2,3 }, normally converted to: * <number><e>1</e><e>2</e><e>3</e></number> (where e can be modified by setting elementName), would instead * translate to <number>1</number><number>2</number><number>3</number>, if "number" is set as an expandable property * Used for unmarshalling (JSON to XML conversion). */ public void setExpandableProperties(List<String> expandableProperties) { this.expandableProperties = expandableProperties; } public String getTypeHints() { return typeHints; } /** * Adds type hints to the resulting XML to aid conversion back to JSON. * Used for unmarshalling (JSON to XML conversion). */ public void setTypeHints(String typeHints) { this.typeHints = typeHints; } }