001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.model.dataformat; 018 019import java.util.Arrays; 020import java.util.List; 021import java.util.Map; 022import javax.xml.bind.annotation.XmlAccessType; 023import javax.xml.bind.annotation.XmlAccessorType; 024import javax.xml.bind.annotation.XmlAttribute; 025import javax.xml.bind.annotation.XmlList; 026import javax.xml.bind.annotation.XmlRootElement; 027 028import org.apache.camel.CamelContext; 029import org.apache.camel.model.DataFormatDefinition; 030import org.apache.camel.spi.DataFormat; 031import org.apache.camel.spi.Metadata; 032 033/** 034 * XML JSon data format can convert from XML to JSON and vice-versa directly, without stepping through intermediate POJOs. 035 * 036 * @version 037 */ 038@Metadata(firstVersion = "2.10.0", label = "dataformat,transformation,xml,json", title = "XML JSon") 039@XmlRootElement(name = "xmljson") 040@XmlAccessorType(XmlAccessType.FIELD) 041@Deprecated 042public class XmlJsonDataFormat extends DataFormatDefinition { 043 044 public static final String TYPE_HINTS = "typeHints"; 045 public static final String REMOVE_NAMESPACE_PREFIXES = "removeNamespacePrefixes"; 046 public static final String SKIP_NAMESPACES = "skipNamespaces"; 047 public static final String TRIM_SPACES = "trimSpaces"; 048 public static final String SKIP_WHITESPACE = "skipWhitespace"; 049 public static final String EXPANDABLE_PROPERTIES = "expandableProperties"; 050 public static final String ARRAY_NAME = "arrayName"; 051 public static final String ELEMENT_NAME = "elementName"; 052 public static final String ROOT_NAME = "rootName"; 053 public static final String NAMESPACE_LENIENT = "namespaceLenient"; 054 public static final String FORCE_TOP_LEVEL_OBJECT = "forceTopLevelObject"; 055 public static final String ENCODING = "encoding"; 056 057 @XmlAttribute 058 private String encoding; 059 @XmlAttribute 060 private String elementName; 061 @XmlAttribute 062 private String arrayName; 063 @XmlAttribute 064 private Boolean forceTopLevelObject; 065 @XmlAttribute 066 private Boolean namespaceLenient; 067 @XmlAttribute 068 private String rootName; 069 @XmlAttribute 070 private Boolean skipWhitespace; 071 @XmlAttribute 072 private Boolean trimSpaces; 073 @XmlAttribute 074 private Boolean skipNamespaces; 075 @XmlAttribute 076 private Boolean removeNamespacePrefixes; 077 @XmlAttribute @XmlList @Metadata(label = "advanced") 078 private List<String> expandableProperties; 079 @XmlAttribute 080 private String typeHints; 081 082 public XmlJsonDataFormat() { 083 super("xmljson"); 084 } 085 086 public XmlJsonDataFormat(Map<String, String> options) { 087 super("xmljson"); 088 if (options.containsKey(ENCODING)) { 089 encoding = options.get(ENCODING); 090 } 091 if (options.containsKey(FORCE_TOP_LEVEL_OBJECT)) { 092 forceTopLevelObject = Boolean.parseBoolean(options.get(FORCE_TOP_LEVEL_OBJECT)); 093 } 094 if (options.containsKey(NAMESPACE_LENIENT)) { 095 namespaceLenient = Boolean.parseBoolean(options.get(NAMESPACE_LENIENT)); 096 } 097 if (options.containsKey(ROOT_NAME)) { 098 rootName = options.get(ROOT_NAME); 099 } 100 if (options.containsKey(ELEMENT_NAME)) { 101 elementName = options.get(ELEMENT_NAME); 102 } 103 if (options.containsKey(ARRAY_NAME)) { 104 arrayName = options.get(ARRAY_NAME); 105 } 106 if (options.containsKey(EXPANDABLE_PROPERTIES)) { 107 expandableProperties = Arrays.asList(options.get(EXPANDABLE_PROPERTIES).split(" ")); 108 } 109 if (options.containsKey(SKIP_WHITESPACE)) { 110 skipWhitespace = Boolean.parseBoolean(options.get(SKIP_WHITESPACE)); 111 } 112 if (options.containsKey(TRIM_SPACES)) { 113 trimSpaces = Boolean.parseBoolean(options.get(TRIM_SPACES)); 114 } 115 if (options.containsKey(SKIP_NAMESPACES)) { 116 skipNamespaces = Boolean.parseBoolean(options.get(SKIP_NAMESPACES)); 117 } 118 if (options.containsKey(REMOVE_NAMESPACE_PREFIXES)) { 119 removeNamespacePrefixes = Boolean.parseBoolean(options.get(REMOVE_NAMESPACE_PREFIXES)); 120 } 121 if (options.containsKey(TYPE_HINTS)) { 122 typeHints = options.get(TYPE_HINTS); 123 } 124 } 125 126 @Override 127 protected void configureDataFormat(DataFormat dataFormat, CamelContext camelContext) { 128 if (encoding != null) { 129 setProperty(camelContext, dataFormat, ENCODING, encoding); 130 } 131 132 if (forceTopLevelObject != null) { 133 setProperty(camelContext, dataFormat, FORCE_TOP_LEVEL_OBJECT, forceTopLevelObject); 134 } 135 136 if (namespaceLenient != null) { 137 setProperty(camelContext, dataFormat, NAMESPACE_LENIENT, namespaceLenient); 138 } 139 140 if (rootName != null) { 141 setProperty(camelContext, dataFormat, ROOT_NAME, rootName); 142 } 143 144 if (elementName != null) { 145 setProperty(camelContext, dataFormat, ELEMENT_NAME, elementName); 146 } 147 148 if (arrayName != null) { 149 setProperty(camelContext, dataFormat, ARRAY_NAME, arrayName); 150 } 151 152 if (expandableProperties != null && expandableProperties.size() != 0) { 153 setProperty(camelContext, dataFormat, EXPANDABLE_PROPERTIES, expandableProperties); 154 } 155 156 if (skipWhitespace != null) { 157 setProperty(camelContext, dataFormat, SKIP_WHITESPACE, skipWhitespace); 158 } 159 160 if (trimSpaces != null) { 161 setProperty(camelContext, dataFormat, TRIM_SPACES, trimSpaces); 162 } 163 164 if (skipNamespaces != null) { 165 setProperty(camelContext, dataFormat, SKIP_NAMESPACES, skipNamespaces); 166 } 167 168 if (removeNamespacePrefixes != null) { 169 setProperty(camelContext, dataFormat, REMOVE_NAMESPACE_PREFIXES, removeNamespacePrefixes); 170 } 171 172 // will end up calling the setTypeHints(String s) which does the parsing from the Enum String key to the Enum value 173 if (typeHints != null) { 174 setProperty(camelContext, dataFormat, TYPE_HINTS, typeHints); 175 } 176 177 //TODO: xmljson: element-namespace mapping is not implemented in the XML DSL 178 // depending on adoption rate of this data format, we'll make this data format NamespaceAware so that it gets 179 // the prefix-namespaceURI mappings from the context, and with a new attribute called "namespacedElements", 180 // we'll associate named elements with prefixes following a format "element1:prefix1,element2:prefix2,..." 181 } 182 183 public String getEncoding() { 184 return encoding; 185 } 186 187 /** 188 * Sets the encoding. 189 * Used for unmarshalling (JSON to XML conversion). 190 */ 191 public void setEncoding(String encoding) { 192 this.encoding = encoding; 193 } 194 195 public String getElementName() { 196 return elementName; 197 } 198 199 /** 200 * Specifies the name of the XML elements representing each array element. 201 * Used for unmarshalling (JSON to XML conversion). 202 */ 203 public void setElementName(String elementName) { 204 this.elementName = elementName; 205 } 206 207 public String getArrayName() { 208 return arrayName; 209 } 210 211 /** 212 * Specifies the name of the top-level XML element. 213 * Used for unmarshalling (JSON to XML conversion). 214 * 215 * 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>. 216 * By setting this option or rootName, you can alter the name of element 'a'. 217 */ 218 public void setArrayName(String arrayName) { 219 this.arrayName = arrayName; 220 } 221 222 public Boolean getForceTopLevelObject() { 223 return forceTopLevelObject; 224 } 225 226 /** 227 * Determines whether the resulting JSON will start off with a top-most element whose name matches the XML root element. 228 * Used for marshalling (XML to JSon conversion). 229 * 230 * If disabled, XML string <a><x>1</x><y>2</y></a> turns into { 'x: '1', 'y': '2' }. 231 * Otherwise, it turns into { 'a': { 'x: '1', 'y': '2' }}. 232 */ 233 public void setForceTopLevelObject(Boolean forceTopLevelObject) { 234 this.forceTopLevelObject = forceTopLevelObject; 235 } 236 237 public Boolean getNamespaceLenient() { 238 return namespaceLenient; 239 } 240 241 /** 242 * Flag to be tolerant to incomplete namespace prefixes. 243 * Used for unmarshalling (JSON to XML conversion). 244 * In most cases, json-lib automatically changes this flag at runtime to match the processing. 245 */ 246 public void setNamespaceLenient(Boolean namespaceLenient) { 247 this.namespaceLenient = namespaceLenient; 248 } 249 250 public String getRootName() { 251 return rootName; 252 } 253 254 /** 255 * Specifies the name of the top-level element. 256 * Used for unmarshalling (JSON to XML conversion). 257 * 258 * 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). 259 * If set to 'root', the JSON string { 'x': 'value1', 'y' : 'value2' } would turn 260 * into <root><x>value1</x><y>value2</y></root>, otherwise the 'root' element would be named 'o'. 261 */ 262 public void setRootName(String rootName) { 263 this.rootName = rootName; 264 } 265 266 public Boolean getSkipWhitespace() { 267 return skipWhitespace; 268 } 269 270 /** 271 * Determines whether white spaces between XML elements will be regarded as text values or disregarded. 272 * Used for marshalling (XML to JSon conversion). 273 */ 274 public void setSkipWhitespace(Boolean skipWhitespace) { 275 this.skipWhitespace = skipWhitespace; 276 } 277 278 public Boolean getTrimSpaces() { 279 return trimSpaces; 280 } 281 282 /** 283 * Determines whether leading and trailing white spaces will be omitted from String values. 284 * Used for marshalling (XML to JSon conversion). 285 */ 286 public void setTrimSpaces(Boolean trimSpaces) { 287 this.trimSpaces = trimSpaces; 288 } 289 290 public Boolean getSkipNamespaces() { 291 return skipNamespaces; 292 } 293 294 /** 295 * Signals whether namespaces should be ignored. By default they will be added to the JSON output using @xmlns elements. 296 * Used for marshalling (XML to JSon conversion). 297 */ 298 public void setSkipNamespaces(Boolean skipNamespaces) { 299 this.skipNamespaces = skipNamespaces; 300 } 301 302 public Boolean getRemoveNamespacePrefixes() { 303 return removeNamespacePrefixes; 304 } 305 306 /** 307 * Removes the namespace prefixes from XML qualified elements, so that the resulting JSON string does not contain them. 308 * Used for marshalling (XML to JSon conversion). 309 */ 310 public void setRemoveNamespacePrefixes(Boolean removeNamespacePrefixes) { 311 this.removeNamespacePrefixes = removeNamespacePrefixes; 312 } 313 314 public List<String> getExpandableProperties() { 315 return expandableProperties; 316 } 317 318 /** 319 * With expandable properties, JSON array elements are converted to XML as a sequence of repetitive XML elements 320 * with the local name equal to the JSON key, for example: { number: 1,2,3 }, normally converted to: 321 * <number><e>1</e><e>2</e><e>3</e></number> (where e can be modified by setting elementName), would instead 322 * translate to <number>1</number><number>2</number><number>3</number>, if "number" is set as an expandable property 323 * Used for unmarshalling (JSON to XML conversion). 324 */ 325 public void setExpandableProperties(List<String> expandableProperties) { 326 this.expandableProperties = expandableProperties; 327 } 328 329 public String getTypeHints() { 330 return typeHints; 331 } 332 333 /** 334 * Adds type hints to the resulting XML to aid conversion back to JSON. 335 * Used for unmarshalling (JSON to XML conversion). 336 */ 337 public void setTypeHints(String typeHints) { 338 this.typeHints = typeHints; 339 } 340 341}