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