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 javax.xml.bind.annotation.XmlAccessType; 020import javax.xml.bind.annotation.XmlAccessorType; 021import javax.xml.bind.annotation.XmlAttribute; 022import javax.xml.bind.annotation.XmlRootElement; 023import javax.xml.bind.annotation.XmlTransient; 024 025import org.apache.camel.CamelContext; 026import org.apache.camel.model.DataFormatDefinition; 027import org.apache.camel.spi.DataFormat; 028import org.apache.camel.spi.Metadata; 029import org.apache.camel.spi.RouteContext; 030import org.apache.camel.util.CollectionStringBuffer; 031import org.apache.camel.util.ObjectHelper; 032 033/** 034 * JSon data format is used for unmarshal a JSon payload to POJO or to marshal 035 * POJO back to JSon payload. 036 * 037 * @version 038 */ 039@Metadata(label = "dataformat,transformation,json", title = "JSon") 040@XmlRootElement(name = "json") 041@XmlAccessorType(XmlAccessType.FIELD) 042public class JsonDataFormat extends DataFormatDefinition { 043 @XmlAttribute 044 private String objectMapper; 045 @XmlAttribute 046 @Metadata(defaultValue = "true") 047 private Boolean useDefaultObjectMapper; 048 @XmlAttribute 049 private Boolean prettyPrint; 050 @XmlAttribute 051 @Metadata(defaultValue = "XStream") 052 private JsonLibrary library = JsonLibrary.XStream; 053 @XmlAttribute 054 private String unmarshalTypeName; 055 @XmlTransient 056 private Class<?> unmarshalType; 057 @XmlAttribute 058 private Class<?> jsonView; 059 @XmlAttribute 060 private String include; 061 @XmlAttribute 062 private Boolean allowJmsType; 063 @XmlAttribute 064 private String collectionTypeName; 065 @XmlTransient 066 private Class<?> collectionType; 067 @XmlAttribute 068 private Boolean useList; 069 @XmlAttribute 070 private Boolean enableJaxbAnnotationModule; 071 @XmlAttribute 072 private String moduleClassNames; 073 @XmlAttribute 074 private String moduleRefs; 075 @XmlAttribute 076 private String enableFeatures; 077 @XmlAttribute 078 private String disableFeatures; 079 @XmlAttribute 080 private String permissions; 081 @XmlAttribute 082 private Boolean allowUnmarshallType; 083 @XmlAttribute 084 private String timezone; 085 086 public JsonDataFormat() { 087 super("json"); 088 } 089 090 public JsonDataFormat(JsonLibrary library) { 091 this.library = library; 092 } 093 094 public String getObjectMapper() { 095 return objectMapper; 096 } 097 098 /** 099 * Lookup and use the existing ObjectMapper with the given id when using 100 * Jackson. 101 */ 102 public void setObjectMapper(String objectMapper) { 103 this.objectMapper = objectMapper; 104 } 105 106 public Boolean getUseDefaultObjectMapper() { 107 return useDefaultObjectMapper; 108 } 109 110 /** 111 * Whether to lookup and use default Jackson ObjectMapper from the registry. 112 */ 113 public void setUseDefaultObjectMapper(Boolean useDefaultObjectMapper) { 114 this.useDefaultObjectMapper = useDefaultObjectMapper; 115 } 116 117 public Boolean getPrettyPrint() { 118 return prettyPrint; 119 } 120 121 /** 122 * To enable pretty printing output nicely formatted. 123 * <p/> 124 * Is by default false. 125 */ 126 public void setPrettyPrint(Boolean prettyPrint) { 127 this.prettyPrint = prettyPrint; 128 } 129 130 public String getUnmarshalTypeName() { 131 return unmarshalTypeName; 132 } 133 134 /** 135 * Class name of the java type to use when unarmshalling 136 */ 137 public void setUnmarshalTypeName(String unmarshalTypeName) { 138 this.unmarshalTypeName = unmarshalTypeName; 139 } 140 141 public Class<?> getUnmarshalType() { 142 return unmarshalType; 143 } 144 145 /** 146 * Class of the java type to use when unarmshalling 147 */ 148 public void setUnmarshalType(Class<?> unmarshalType) { 149 this.unmarshalType = unmarshalType; 150 } 151 152 public JsonLibrary getLibrary() { 153 return library; 154 } 155 156 /** 157 * Which json library to use. 158 */ 159 public void setLibrary(JsonLibrary library) { 160 this.library = library; 161 } 162 163 public Class<?> getJsonView() { 164 return jsonView; 165 } 166 167 /** 168 * When marshalling a POJO to JSON you might want to exclude certain fields 169 * from the JSON output. With Jackson you can use JSON views to accomplish 170 * this. This option is to refer to the class which has @JsonView 171 * annotations 172 */ 173 public void setJsonView(Class<?> jsonView) { 174 this.jsonView = jsonView; 175 } 176 177 public String getInclude() { 178 return include; 179 } 180 181 /** 182 * If you want to marshal a pojo to JSON, and the pojo has some fields with 183 * null values. And you want to skip these null values, you can set this 184 * option to <tt>NOT_NULL</tt> 185 */ 186 public void setInclude(String include) { 187 this.include = include; 188 } 189 190 public Boolean getAllowJmsType() { 191 return allowJmsType; 192 } 193 194 /** 195 * Used for JMS users to allow the JMSType header from the JMS spec to 196 * specify a FQN classname to use to unmarshal to. 197 */ 198 public void setAllowJmsType(Boolean allowJmsType) { 199 this.allowJmsType = allowJmsType; 200 } 201 202 public String getCollectionTypeName() { 203 return collectionTypeName; 204 } 205 206 /** 207 * Refers to a custom collection type to lookup in the registry to use. This 208 * option should rarely be used, but allows to use different collection 209 * types than java.util.Collection based as default. 210 */ 211 public void setCollectionTypeName(String collectionTypeName) { 212 this.collectionTypeName = collectionTypeName; 213 } 214 215 public Boolean getUseList() { 216 return useList; 217 } 218 219 /** 220 * To unarmshal to a List of Map or a List of Pojo. 221 */ 222 public void setUseList(Boolean useList) { 223 this.useList = useList; 224 } 225 226 public Boolean getEnableJaxbAnnotationModule() { 227 return enableJaxbAnnotationModule; 228 } 229 230 /** 231 * Whether to enable the JAXB annotations module when using jackson. When 232 * enabled then JAXB annotations can be used by Jackson. 233 */ 234 public void setEnableJaxbAnnotationModule(Boolean enableJaxbAnnotationModule) { 235 this.enableJaxbAnnotationModule = enableJaxbAnnotationModule; 236 } 237 238 public String getModuleClassNames() { 239 return moduleClassNames; 240 } 241 242 /** 243 * To use custom Jackson modules com.fasterxml.jackson.databind.Module 244 * specified as a String with FQN class names. Multiple classes can be 245 * separated by comma. 246 */ 247 public void setModuleClassNames(String moduleClassNames) { 248 this.moduleClassNames = moduleClassNames; 249 } 250 251 public String getModuleRefs() { 252 return moduleRefs; 253 } 254 255 /** 256 * To use custom Jackson modules referred from the Camel registry. Multiple 257 * modules can be separated by comma. 258 */ 259 public void setModuleRefs(String moduleRefs) { 260 this.moduleRefs = moduleRefs; 261 } 262 263 public String getEnableFeatures() { 264 return enableFeatures; 265 } 266 267 /** 268 * Set of features to enable on the Jackson 269 * <tt>com.fasterxml.jackson.databind.ObjectMapper</tt>. 270 * <p/> 271 * The features should be a name that matches a enum from 272 * <tt>com.fasterxml.jackson.databind.SerializationFeature</tt>, 273 * <tt>com.fasterxml.jackson.databind.DeserializationFeature</tt>, or 274 * <tt>com.fasterxml.jackson.databind.MapperFeature</tt> 275 * <p/> 276 * Multiple features can be separated by comma 277 */ 278 public void setEnableFeatures(String enableFeatures) { 279 this.enableFeatures = enableFeatures; 280 } 281 282 public String getDisableFeatures() { 283 return disableFeatures; 284 } 285 286 /** 287 * Set of features to disable on the Jackson 288 * <tt>com.fasterxml.jackson.databind.ObjectMapper</tt>. 289 * <p/> 290 * The features should be a name that matches a enum from 291 * <tt>com.fasterxml.jackson.databind.SerializationFeature</tt>, 292 * <tt>com.fasterxml.jackson.databind.DeserializationFeature</tt>, or 293 * <tt>com.fasterxml.jackson.databind.MapperFeature</tt> 294 * <p/> 295 * Multiple features can be separated by comma 296 */ 297 public void setDisableFeatures(String disableFeatures) { 298 this.disableFeatures = disableFeatures; 299 } 300 301 public String getPermissions() { 302 return permissions; 303 } 304 305 /** 306 * Adds permissions that controls which Java packages and classes XStream is 307 * allowed to use during unmarshal from xml/json to Java beans. 308 * <p/> 309 * A permission must be configured either here or globally using a JVM 310 * system property. The permission can be specified in a syntax where a plus 311 * sign is allow, and minus sign is deny. <br/> 312 * Wildcards is supported by using <tt>.*</tt> as prefix. For example to 313 * allow <tt>com.foo</tt> and all subpackages then specfy 314 * <tt>+com.foo.*</tt>. Multiple permissions can be configured separated by 315 * comma, such as <tt>+com.foo.*,-com.foo.bar.MySecretBean</tt>. <br/> 316 * The following default permission is always included: 317 * <tt>"-*,java.lang.*,java.util.*"</tt> unless its overridden by specifying 318 * a JVM system property with they key 319 * <tt>org.apache.camel.xstream.permissions</tt>. 320 */ 321 public void setPermissions(String permissions) { 322 this.permissions = permissions; 323 } 324 325 /** 326 * To add permission for the given pojo classes. 327 * 328 * @param type the pojo class(es) xstream should use as allowed permission 329 * @see #setPermissions(String) 330 */ 331 public void setPermissions(Class<?>... type) { 332 CollectionStringBuffer csb = new CollectionStringBuffer(","); 333 for (Class<?> clazz : type) { 334 csb.append("+"); 335 csb.append(clazz.getName()); 336 } 337 setPermissions(csb.toString()); 338 } 339 340 public Boolean getAllowUnmarshallType() { 341 return allowUnmarshallType; 342 } 343 344 /** 345 * If enabled then Jackson is allowed to attempt to use the 346 * CamelJacksonUnmarshalType header during the unmarshalling. 347 * <p/> 348 * This should only be enabled when desired to be used. 349 */ 350 public void setAllowUnmarshallType(Boolean allowUnmarshallType) { 351 this.allowUnmarshallType = allowUnmarshallType; 352 } 353 354 public String getTimezone() { 355 return timezone; 356 } 357 358 /** 359 * If set then Jackson will use the Timezone when marshalling/unmarshalling. 360 * This option will have no effect on the others Json DataFormat, like gson, 361 * fastjson and xstream. 362 */ 363 public void setTimezone(String timezone) { 364 this.timezone = timezone; 365 } 366 367 @Override 368 public String getDataFormatName() { 369 // json data format is special as the name can be from different bundles 370 return "json-" + library.name().toLowerCase(); 371 } 372 373 @Override 374 protected DataFormat createDataFormat(RouteContext routeContext) { 375 if (library == JsonLibrary.XStream) { 376 setProperty(routeContext.getCamelContext(), this, "dataFormatName", "json-xstream"); 377 } else if (library == JsonLibrary.Jackson) { 378 setProperty(routeContext.getCamelContext(), this, "dataFormatName", "json-jackson"); 379 } else if (library == JsonLibrary.Gson) { 380 setProperty(routeContext.getCamelContext(), this, "dataFormatName", "json-gson"); 381 } else if (library == JsonLibrary.Fastjson) { 382 setProperty(routeContext.getCamelContext(), this, "dataFormatName", "json-fastjson"); 383 } else { 384 setProperty(routeContext.getCamelContext(), this, "dataFormatName", "json-johnzon"); 385 } 386 387 if (unmarshalType == null && unmarshalTypeName != null) { 388 try { 389 unmarshalType = routeContext.getCamelContext().getClassResolver().resolveMandatoryClass(unmarshalTypeName); 390 } catch (ClassNotFoundException e) { 391 throw ObjectHelper.wrapRuntimeCamelException(e); 392 } 393 } 394 if (collectionType == null && collectionTypeName != null) { 395 try { 396 collectionType = routeContext.getCamelContext().getClassResolver().resolveMandatoryClass(collectionTypeName); 397 } catch (ClassNotFoundException e) { 398 throw ObjectHelper.wrapRuntimeCamelException(e); 399 } 400 } 401 402 return super.createDataFormat(routeContext); 403 } 404 405 @Override 406 protected void configureDataFormat(DataFormat dataFormat, CamelContext camelContext) { 407 if (objectMapper != null) { 408 // must be a reference value 409 String ref = objectMapper.startsWith("#") ? objectMapper : "#" + objectMapper; 410 setProperty(camelContext, dataFormat, "objectMapper", ref); 411 } 412 if (useDefaultObjectMapper != null) { 413 setProperty(camelContext, dataFormat, "useDefaultObjectMapper", useDefaultObjectMapper); 414 } 415 if (unmarshalType != null) { 416 setProperty(camelContext, dataFormat, "unmarshalType", unmarshalType); 417 } 418 if (prettyPrint != null) { 419 setProperty(camelContext, dataFormat, "prettyPrint", prettyPrint); 420 } 421 if (jsonView != null) { 422 setProperty(camelContext, dataFormat, "jsonView", jsonView); 423 } 424 if (include != null) { 425 setProperty(camelContext, dataFormat, "include", include); 426 } 427 if (allowJmsType != null) { 428 setProperty(camelContext, dataFormat, "allowJmsType", allowJmsType); 429 } 430 if (collectionType != null) { 431 setProperty(camelContext, dataFormat, "collectionType", collectionType); 432 } 433 if (useList != null) { 434 setProperty(camelContext, dataFormat, "useList", useList); 435 } 436 if (enableJaxbAnnotationModule != null) { 437 setProperty(camelContext, dataFormat, "enableJaxbAnnotationModule", enableJaxbAnnotationModule); 438 } 439 if (moduleClassNames != null) { 440 setProperty(camelContext, dataFormat, "moduleClassNames", moduleClassNames); 441 } 442 if (moduleRefs != null) { 443 setProperty(camelContext, dataFormat, "moduleRefs", moduleRefs); 444 } 445 if (enableFeatures != null) { 446 setProperty(camelContext, dataFormat, "enableFeatures", enableFeatures); 447 } 448 if (disableFeatures != null) { 449 setProperty(camelContext, dataFormat, "disableFeatures", disableFeatures); 450 } 451 if (permissions != null) { 452 setProperty(camelContext, dataFormat, "permissions", permissions); 453 } 454 if (allowUnmarshallType != null) { 455 setProperty(camelContext, dataFormat, "allowUnmarshallType", allowUnmarshallType); 456 } 457 // if we have the unmarshal type, but no permission set, then use it to 458 // be allowed 459 if (permissions == null && unmarshalType != null) { 460 String allow = "+" + unmarshalType.getName(); 461 setProperty(camelContext, dataFormat, "permissions", allow); 462 } 463 } 464 465}