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.ArrayList; 020import java.util.Arrays; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.Map.Entry; 025 026import javax.xml.bind.annotation.XmlAccessType; 027import javax.xml.bind.annotation.XmlAccessorType; 028import javax.xml.bind.annotation.XmlAttribute; 029import javax.xml.bind.annotation.XmlElement; 030import javax.xml.bind.annotation.XmlRootElement; 031import javax.xml.bind.annotation.XmlTransient; 032import javax.xml.bind.annotation.XmlType; 033import javax.xml.bind.annotation.adapters.XmlAdapter; 034import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 035 036import org.apache.camel.model.DataFormatDefinition; 037import org.apache.camel.spi.Metadata; 038import org.apache.camel.util.CollectionStringBuffer; 039 040/** 041 * XStream data format is used for unmarshal a XML payload to POJO or to marshal 042 * POJO back to XML payload. 043 */ 044@Metadata(firstVersion = "1.3.0", label = "dataformat,transformation,xml,json", title = "XStream") 045@XmlRootElement(name = "xstream") 046@XmlAccessorType(XmlAccessType.NONE) 047public class XStreamDataFormat extends DataFormatDefinition { 048 @XmlAttribute 049 private String permissions; 050 @XmlAttribute 051 private String encoding; 052 @XmlAttribute 053 private String driver; 054 @XmlAttribute 055 private String driverRef; 056 @XmlAttribute 057 private String mode; 058 059 @XmlJavaTypeAdapter(ConvertersAdapter.class) 060 @XmlElement(name = "converters") 061 private List<String> converters; 062 @XmlJavaTypeAdapter(AliasAdapter.class) 063 @XmlElement(name = "aliases") 064 private Map<String, String> aliases; 065 @XmlJavaTypeAdapter(OmitFieldsAdapter.class) 066 @XmlElement(name = "omitFields") 067 private Map<String, String[]> omitFields; 068 @XmlJavaTypeAdapter(ImplicitCollectionsAdapter.class) 069 @XmlElement(name = "implicitCollections") 070 private Map<String, String[]> implicitCollections; 071 072 public XStreamDataFormat() { 073 super("xstream"); 074 } 075 076 public XStreamDataFormat(String encoding) { 077 this(); 078 setEncoding(encoding); 079 } 080 081 @Override 082 public String getDataFormatName() { 083 return "json".equals(driver) ? "json-xstream" : "xstream"; 084 } 085 086 public String getEncoding() { 087 return encoding; 088 } 089 090 /** 091 * Sets the encoding to use 092 */ 093 public void setEncoding(String encoding) { 094 this.encoding = encoding; 095 } 096 097 public String getDriver() { 098 return driver; 099 } 100 101 /** 102 * To use a custom XStream driver. The instance must be of type 103 * com.thoughtworks.xstream.io.HierarchicalStreamDriver 104 */ 105 public void setDriver(String driver) { 106 this.driver = driver; 107 } 108 109 public String getDriverRef() { 110 return driverRef; 111 } 112 113 /** 114 * To refer to a custom XStream driver to lookup in the registry. The 115 * instance must be of type 116 * com.thoughtworks.xstream.io.HierarchicalStreamDriver 117 */ 118 public void setDriverRef(String driverRef) { 119 this.driverRef = driverRef; 120 } 121 122 public String getMode() { 123 return mode; 124 } 125 126 /** 127 * Mode for dealing with duplicate references The possible values are: 128 * <ul> 129 * <li>NO_REFERENCES</li> 130 * <li>ID_REFERENCES</li> 131 * <li>XPATH_RELATIVE_REFERENCES</li> 132 * <li>XPATH_ABSOLUTE_REFERENCES</li> 133 * <li>SINGLE_NODE_XPATH_RELATIVE_REFERENCES</li> 134 * <li>SINGLE_NODE_XPATH_ABSOLUTE_REFERENCES</li> 135 * </ul> 136 */ 137 public void setMode(String mode) { 138 this.mode = mode; 139 } 140 141 public List<String> getConverters() { 142 return converters; 143 } 144 145 /** 146 * List of class names for using custom XStream converters. The classes must 147 * be of type com.thoughtworks.xstream.converters.Converter 148 */ 149 public void setConverters(List<String> converters) { 150 this.converters = converters; 151 } 152 153 public Map<String, String> getAliases() { 154 return aliases; 155 } 156 157 /** 158 * Alias a Class to a shorter name to be used in XML elements. 159 */ 160 public void setAliases(Map<String, String> aliases) { 161 this.aliases = aliases; 162 } 163 164 public Map<String, String[]> getOmitFields() { 165 return omitFields; 166 } 167 168 /** 169 * Prevents a field from being serialized. To omit a field you must always 170 * provide the declaring type and not necessarily the type that is 171 * converted. 172 */ 173 public void setOmitFields(Map<String, String[]> omitFields) { 174 this.omitFields = omitFields; 175 } 176 177 public Map<String, String[]> getImplicitCollections() { 178 return implicitCollections; 179 } 180 181 /** 182 * Adds a default implicit collection which is used for any unmapped XML 183 * tag. 184 */ 185 public void setImplicitCollections(Map<String, String[]> implicitCollections) { 186 this.implicitCollections = implicitCollections; 187 } 188 189 public String getPermissions() { 190 return permissions; 191 } 192 193 /** 194 * Adds permissions that controls which Java packages and classes XStream is 195 * allowed to use during unmarshal from xml/json to Java beans. 196 * <p/> 197 * A permission must be configured either here or globally using a JVM 198 * system property. The permission can be specified in a syntax where a plus 199 * sign is allow, and minus sign is deny. <br/> 200 * Wildcards is supported by using <tt>.*</tt> as prefix. For example to 201 * allow <tt>com.foo</tt> and all subpackages then specify 202 * <tt>+com.foo.*</tt>. Multiple permissions can be configured separated by 203 * comma, such as <tt>+com.foo.*,-com.foo.bar.MySecretBean</tt>. <br/> 204 * The following default permission is always included: 205 * <tt>"-*,java.lang.*,java.util.*"</tt> unless its overridden by specifying 206 * a JVM system property with they key 207 * <tt>org.apache.camel.xstream.permissions</tt>. 208 */ 209 public void setPermissions(String permissions) { 210 this.permissions = permissions; 211 } 212 213 /** 214 * To add permission for the given pojo classes. 215 * 216 * @param type the pojo class(es) xstream should use as allowed permission 217 * @see #setPermissions(String) 218 */ 219 public void setPermissions(Class<?>... type) { 220 CollectionStringBuffer csb = new CollectionStringBuffer(","); 221 for (Class<?> clazz : type) { 222 csb.append("+"); 223 csb.append(clazz.getName()); 224 } 225 setPermissions(csb.toString()); 226 } 227 228 @XmlTransient 229 public static class ConvertersAdapter extends XmlAdapter<ConverterList, List<String>> { 230 @Override 231 public ConverterList marshal(List<String> v) throws Exception { 232 if (v == null) { 233 return null; 234 } 235 236 List<ConverterEntry> list = new ArrayList<>(); 237 for (String str : v) { 238 ConverterEntry entry = new ConverterEntry(); 239 entry.setClsName(str); 240 list.add(entry); 241 } 242 ConverterList converterList = new ConverterList(); 243 converterList.setList(list); 244 return converterList; 245 } 246 247 @Override 248 public List<String> unmarshal(ConverterList v) throws Exception { 249 if (v == null) { 250 return null; 251 } 252 253 List<String> list = new ArrayList<>(); 254 for (ConverterEntry entry : v.getList()) { 255 list.add(entry.getClsName()); 256 } 257 return list; 258 } 259 } 260 261 @XmlAccessorType(XmlAccessType.NONE) 262 @XmlType(name = "converterList", namespace = "http://camel.apache.org/schema/spring") 263 public static class ConverterList { 264 @XmlElement(name = "converter", namespace = "http://camel.apache.org/schema/spring") 265 private List<ConverterEntry> list; 266 267 public List<ConverterEntry> getList() { 268 return list; 269 } 270 271 public void setList(List<ConverterEntry> list) { 272 this.list = list; 273 } 274 } 275 276 @XmlAccessorType(XmlAccessType.NONE) 277 @XmlType(name = "converterEntry", namespace = "http://camel.apache.org/schema/spring") 278 public static class ConverterEntry { 279 @XmlAttribute(name = "class") 280 private String clsName; 281 282 public String getClsName() { 283 return clsName; 284 } 285 286 public void setClsName(String clsName) { 287 this.clsName = clsName; 288 } 289 } 290 291 @XmlTransient 292 public static class ImplicitCollectionsAdapter extends XmlAdapter<ImplicitCollectionList, Map<String, String[]>> { 293 294 @Override 295 public ImplicitCollectionList marshal(Map<String, String[]> v) throws Exception { 296 if (v == null || v.isEmpty()) { 297 return null; 298 } 299 300 List<ImplicitCollectionEntry> list = new ArrayList<>(); 301 for (Entry<String, String[]> e : v.entrySet()) { 302 ImplicitCollectionEntry entry = new ImplicitCollectionEntry(e.getKey(), e.getValue()); 303 list.add(entry); 304 } 305 306 ImplicitCollectionList collectionList = new ImplicitCollectionList(); 307 collectionList.setList(list); 308 309 return collectionList; 310 } 311 312 @Override 313 public Map<String, String[]> unmarshal(ImplicitCollectionList v) throws Exception { 314 if (v == null) { 315 return null; 316 } 317 318 Map<String, String[]> map = new HashMap<>(); 319 for (ImplicitCollectionEntry entry : v.getList()) { 320 map.put(entry.getClsName(), entry.getFields()); 321 } 322 return map; 323 } 324 } 325 326 @XmlAccessorType(XmlAccessType.NONE) 327 @XmlType(name = "implicitCollectionList", namespace = "http://camel.apache.org/schema/spring") 328 public static class ImplicitCollectionList { 329 @XmlElement(name = "class", namespace = "http://camel.apache.org/schema/spring") 330 private List<ImplicitCollectionEntry> list; 331 332 public List<ImplicitCollectionEntry> getList() { 333 return list; 334 } 335 336 public void setList(List<ImplicitCollectionEntry> list) { 337 this.list = list; 338 } 339 } 340 341 @XmlAccessorType(XmlAccessType.NONE) 342 @XmlType(name = "implicitCollectionEntry", namespace = "http://camel.apache.org/schema/spring") 343 public static class ImplicitCollectionEntry { 344 @XmlAttribute(name = "name") 345 private String clsName; 346 347 @XmlElement(name = "field", namespace = "http://camel.apache.org/schema/spring") 348 private String[] fields; 349 350 public ImplicitCollectionEntry() { 351 } 352 353 public ImplicitCollectionEntry(String clsName, String[] fields) { 354 this.clsName = clsName; 355 this.fields = fields; 356 } 357 358 public String getClsName() { 359 return clsName; 360 } 361 362 public void setClsName(String clsName) { 363 this.clsName = clsName; 364 } 365 366 public String[] getFields() { 367 return fields; 368 } 369 370 public void setFields(String[] fields) { 371 this.fields = fields; 372 } 373 374 @Override 375 public String toString() { 376 return "Alias[ImplicitCollection=" + clsName + ", fields=" + Arrays.asList(this.fields) + "]"; 377 } 378 } 379 380 @XmlTransient 381 public static class AliasAdapter extends XmlAdapter<AliasList, Map<String, String>> { 382 383 @Override 384 public AliasList marshal(Map<String, String> value) throws Exception { 385 if (value == null || value.isEmpty()) { 386 return null; 387 } 388 389 List<AliasEntry> ret = new ArrayList<>(value.size()); 390 for (Map.Entry<String, String> entry : value.entrySet()) { 391 ret.add(new AliasEntry(entry.getKey(), entry.getValue())); 392 } 393 AliasList jaxbMap = new AliasList(); 394 jaxbMap.setList(ret); 395 return jaxbMap; 396 } 397 398 @Override 399 public Map<String, String> unmarshal(AliasList value) throws Exception { 400 if (value == null || value.getList() == null || value.getList().isEmpty()) { 401 return null; 402 } 403 404 Map<String, String> answer = new HashMap<>(); 405 for (AliasEntry alias : value.getList()) { 406 answer.put(alias.getName(), alias.getClsName()); 407 } 408 return answer; 409 } 410 } 411 412 @XmlAccessorType(XmlAccessType.NONE) 413 @XmlType(name = "aliasList", namespace = "http://camel.apache.org/schema/spring") 414 public static class AliasList { 415 @XmlElement(name = "alias", namespace = "http://camel.apache.org/schema/spring") 416 private List<AliasEntry> list; 417 418 public List<AliasEntry> getList() { 419 return list; 420 } 421 422 public void setList(List<AliasEntry> list) { 423 this.list = list; 424 } 425 } 426 427 @XmlAccessorType(XmlAccessType.NONE) 428 @XmlType(name = "aliasEntry", namespace = "http://camel.apache.org/schema/spring") 429 public static class AliasEntry { 430 431 @XmlAttribute 432 private String name; 433 434 @XmlAttribute(name = "class") 435 private String clsName; 436 437 public AliasEntry() { 438 } 439 440 public AliasEntry(String key, String clsName) { 441 this.name = key; 442 this.clsName = clsName; 443 } 444 445 public String getName() { 446 return name; 447 } 448 449 public void setName(String name) { 450 this.name = name; 451 } 452 453 public String getClsName() { 454 return clsName; 455 } 456 457 public void setClsName(String clsName) { 458 this.clsName = clsName; 459 } 460 461 @Override 462 public String toString() { 463 return "Alias[name=" + name + ", class=" + clsName + "]"; 464 } 465 } 466 467 @XmlTransient 468 public static class OmitFieldsAdapter extends XmlAdapter<OmitFieldList, Map<String, String[]>> { 469 470 @Override 471 public OmitFieldList marshal(Map<String, String[]> v) throws Exception { 472 if (v == null || v.isEmpty()) { 473 return null; 474 } 475 476 List<OmitFieldEntry> list = new ArrayList<>(); 477 for (Entry<String, String[]> e : v.entrySet()) { 478 OmitFieldEntry entry = new OmitFieldEntry(e.getKey(), e.getValue()); 479 list.add(entry); 480 } 481 482 OmitFieldList collectionList = new OmitFieldList(); 483 collectionList.setList(list); 484 485 return collectionList; 486 } 487 488 @Override 489 public Map<String, String[]> unmarshal(OmitFieldList v) throws Exception { 490 if (v == null || v.getList() == null || v.getList().isEmpty()) { 491 return null; 492 } 493 494 Map<String, String[]> map = new HashMap<>(); 495 for (OmitFieldEntry entry : v.getList()) { 496 map.put(entry.getClsName(), entry.getFields()); 497 } 498 return map; 499 } 500 } 501 502 @XmlAccessorType(XmlAccessType.NONE) 503 @XmlType(name = "omitFieldList", namespace = "http://camel.apache.org/schema/spring") 504 public static class OmitFieldList { 505 @XmlElement(name = "omitField", namespace = "http://camel.apache.org/schema/spring") 506 private List<OmitFieldEntry> list; 507 508 public List<OmitFieldEntry> getList() { 509 return list; 510 } 511 512 public void setList(List<OmitFieldEntry> list) { 513 this.list = list; 514 } 515 } 516 517 @XmlAccessorType(XmlAccessType.NONE) 518 @XmlType(name = "omitFieldEntry", namespace = "http://camel.apache.org/schema/spring") 519 public static class OmitFieldEntry { 520 521 @XmlAttribute(name = "class") 522 private String clsName; 523 524 @XmlElement(name = "field", namespace = "http://camel.apache.org/schema/spring") 525 private String[] fields; 526 527 public OmitFieldEntry() { 528 } 529 530 public OmitFieldEntry(String clsName, String[] fields) { 531 this.clsName = clsName; 532 this.fields = fields; 533 } 534 535 public String getClsName() { 536 return clsName; 537 } 538 539 public void setClsName(String clsName) { 540 this.clsName = clsName; 541 } 542 543 public String[] getFields() { 544 return fields; 545 } 546 547 public void setFields(String[] fields) { 548 this.fields = fields; 549 } 550 551 @Override 552 public String toString() { 553 return "OmitField[" + clsName + ", fields=" + Arrays.asList(this.fields) + "]"; 554 } 555 } 556}