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