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.List; 021 022import javax.xml.bind.annotation.XmlAccessType; 023import javax.xml.bind.annotation.XmlAccessorType; 024import javax.xml.bind.annotation.XmlAttribute; 025import javax.xml.bind.annotation.XmlElement; 026import javax.xml.bind.annotation.XmlRootElement; 027import javax.xml.bind.annotation.XmlTransient; 028 029import org.apache.camel.CamelContext; 030import org.apache.camel.model.DataFormatDefinition; 031import org.apache.camel.spi.DataFormat; 032import org.apache.camel.spi.Metadata; 033import org.apache.camel.spi.RouteContext; 034import org.apache.camel.util.ObjectHelper; 035 036/** 037 * YAML is a data format to marshal and unmarshal Java objects to and from YAML. 038 * 039 * @version 040 */ 041@Metadata(firstVersion = "2.17.0", label = "dataformat,transformation,yaml", title = "YAML") 042@XmlRootElement(name = "yaml") 043@XmlAccessorType(XmlAccessType.FIELD) 044public class YAMLDataFormat extends DataFormatDefinition { 045 @XmlAttribute @Metadata(defaultValue = "SnakeYAML") 046 private YAMLLibrary library = YAMLLibrary.SnakeYAML; 047 @XmlTransient 048 private ClassLoader classLoader; 049 @XmlTransient 050 private Class<?> unmarshalType; 051 @XmlAttribute 052 private String unmarshalTypeName; 053 @XmlAttribute 054 private String constructor; 055 @XmlAttribute 056 private String representer; 057 @XmlAttribute 058 private String dumperOptions; 059 @XmlAttribute 060 private String resolver; 061 @XmlAttribute @Metadata(defaultValue = "true") 062 private Boolean useApplicationContextClassLoader = true; 063 @XmlAttribute @Metadata(defaultValue = "false") 064 private Boolean prettyFlow = false; 065 @XmlAttribute @Metadata(defaultValue = "false") 066 private Boolean allowAnyType = false; 067 @XmlElement(name = "typeFilter") 068 private List<YAMLTypeFilterDefinition> typeFilters; 069 070 public YAMLDataFormat() { 071 this(YAMLLibrary.SnakeYAML); 072 } 073 074 public YAMLDataFormat(YAMLLibrary library) { 075 super("yaml-" + library.name().toLowerCase()); 076 this.library = library; 077 } 078 079 public YAMLDataFormat(YAMLLibrary library, Class<?> unmarshalType) { 080 super("yaml-" + library.name().toLowerCase()); 081 this.library = library; 082 this.unmarshalType = unmarshalType; 083 } 084 085 public YAMLLibrary getLibrary() { 086 return library; 087 } 088 089 /** 090 * Which yaml library to use. 091 * <p/> 092 * By default it is SnakeYAML 093 */ 094 public void setLibrary(YAMLLibrary library) { 095 this.library = library; 096 setDataFormatName("yaml-" + library.name().toLowerCase()); 097 } 098 099 public Class<?> getUnmarshalType() { 100 return unmarshalType; 101 } 102 103 /** 104 * Class of the object to be created 105 */ 106 public void setUnmarshalType(Class<?> type) { 107 this.unmarshalType = type; 108 } 109 110 public String getUnmarshalTypeName() { 111 return unmarshalTypeName; 112 } 113 114 /** 115 * Class name of the java type to use when unarmshalling 116 */ 117 public void setUnmarshalTypeName(String unmarshalTypeName) { 118 this.unmarshalTypeName = unmarshalTypeName; 119 } 120 121 public ClassLoader getClassLoader() { 122 return classLoader; 123 } 124 125 /** 126 * Set a custom classloader 127 */ 128 public void setClassLoader(ClassLoader classLoader) { 129 this.classLoader = classLoader; 130 } 131 132 public String getConstructor() { 133 return constructor; 134 } 135 136 /** 137 * BaseConstructor to construct incoming documents. 138 */ 139 public void setConstructor(String constructor) { 140 this.constructor = constructor; 141 } 142 143 public String getRepresenter() { 144 return representer; 145 } 146 147 /** 148 * Representer to emit outgoing objects. 149 */ 150 public void setRepresenter(String representer) { 151 this.representer = representer; 152 } 153 154 public String getDumperOptions() { 155 return dumperOptions; 156 } 157 158 /** 159 * DumperOptions to configure outgoing objects. 160 */ 161 public void setDumperOptions(String dumperOptions) { 162 this.dumperOptions = dumperOptions; 163 } 164 165 public String getResolver() { 166 return resolver; 167 } 168 169 /** 170 * Resolver to detect implicit type 171 */ 172 public void setResolver(String resolver) { 173 this.resolver = resolver; 174 } 175 176 public boolean isUseApplicationContextClassLoader() { 177 return useApplicationContextClassLoader; 178 } 179 180 /** 181 * Use ApplicationContextClassLoader as custom ClassLoader 182 */ 183 public void setUseApplicationContextClassLoader(boolean useApplicationContextClassLoader) { 184 this.useApplicationContextClassLoader = useApplicationContextClassLoader; 185 } 186 187 public boolean isPrettyFlow() { 188 return prettyFlow; 189 } 190 191 /** 192 * Force the emitter to produce a pretty YAML document when using the flow 193 * style. 194 */ 195 public void setPrettyFlow(boolean prettyFlow) { 196 this.prettyFlow = prettyFlow; 197 } 198 199 public boolean isAllowAnyType() { 200 return allowAnyType; 201 } 202 203 /** 204 * Allow any class to be un-marshaled 205 */ 206 public void setAllowAnyType(boolean allowAnyType) { 207 this.allowAnyType = allowAnyType; 208 } 209 210 public List<YAMLTypeFilterDefinition> getTypeFilters() { 211 return typeFilters; 212 } 213 214 /** 215 * Set the types SnakeYAML is allowed to un-marshall 216 */ 217 public void setTypeFilters(List<YAMLTypeFilterDefinition> typeFilters) { 218 this.typeFilters = typeFilters; 219 } 220 221 @Override 222 protected DataFormat createDataFormat(RouteContext routeContext) { 223 if (library == YAMLLibrary.SnakeYAML) { 224 setProperty(routeContext.getCamelContext(), this, "dataFormatName", "yaml-snakeyaml"); 225 } 226 227 return super.createDataFormat(routeContext); 228 } 229 230 @Override 231 protected void configureDataFormat(DataFormat dataFormat, CamelContext camelContext) { 232 if (library == YAMLLibrary.SnakeYAML) { 233 configureSnakeDataFormat(dataFormat, camelContext); 234 } 235 } 236 237 protected void configureSnakeDataFormat(DataFormat dataFormat, CamelContext camelContext) { 238 Class<?> yamlUnmarshalType = unmarshalType; 239 if (yamlUnmarshalType == null && unmarshalTypeName != null) { 240 try { 241 yamlUnmarshalType = camelContext.getClassResolver().resolveMandatoryClass(unmarshalTypeName); 242 } catch (ClassNotFoundException e) { 243 throw ObjectHelper.wrapRuntimeCamelException(e); 244 } 245 } 246 247 setProperty(dataFormat, camelContext, "unmarshalType", yamlUnmarshalType); 248 setProperty(dataFormat, camelContext, "classLoader", classLoader); 249 setProperty(dataFormat, camelContext, "useApplicationContextClassLoader", useApplicationContextClassLoader); 250 setProperty(dataFormat, camelContext, "prettyFlow", prettyFlow); 251 setProperty(dataFormat, camelContext, "allowAnyType", allowAnyType); 252 253 if (typeFilters != null && !typeFilters.isEmpty()) { 254 List<String> typeFilterDefinitions = new ArrayList<>(typeFilters.size()); 255 for (YAMLTypeFilterDefinition definition : typeFilters) { 256 String value = definition.getValue(); 257 258 if (!value.startsWith("type") && !value.startsWith("regexp")) { 259 YAMLTypeFilterType type = definition.getType(); 260 if (type == null) { 261 type = YAMLTypeFilterType.type; 262 } 263 264 value = type.name() + ":" + value; 265 } 266 267 typeFilterDefinitions.add(value); 268 } 269 270 setProperty(dataFormat, camelContext, "typeFilterDefinitions", typeFilterDefinitions); 271 } 272 273 setPropertyRef(dataFormat, camelContext, "constructor", constructor); 274 setPropertyRef(dataFormat, camelContext, "representer", representer); 275 setPropertyRef(dataFormat, camelContext, "dumperOptions", dumperOptions); 276 setPropertyRef(dataFormat, camelContext, "resolver", resolver); 277 } 278 279 protected void setProperty(DataFormat dataFormat, CamelContext camelContext, String propertyName, Object propertyValue) { 280 if (ObjectHelper.isNotEmpty(propertyValue)) { 281 setProperty(camelContext, dataFormat, propertyName, propertyValue); 282 } 283 } 284 285 protected void setPropertyRef(DataFormat dataFormat, CamelContext camelContext, String propertyName, String propertyValue) { 286 if (ObjectHelper.isNotEmpty(propertyValue)) { 287 // must be a reference value 288 String ref = propertyValue.startsWith("#") ? propertyValue : "#" + propertyValue; 289 setProperty(camelContext, dataFormat, propertyName, ref); 290 } 291 } 292 293}