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