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