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