Yaml.java revision 74f18c7830b06bedef2e4e20de6bd2b80928d089
1/** 2 * Copyright (c) 2008-2010, http://www.snakeyaml.org 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package org.yaml.snakeyaml; 18 19import java.io.InputStream; 20import java.io.Reader; 21import java.io.StringReader; 22import java.io.StringWriter; 23import java.io.Writer; 24import java.util.ArrayList; 25import java.util.Iterator; 26import java.util.List; 27import java.util.regex.Pattern; 28 29import org.yaml.snakeyaml.composer.Composer; 30import org.yaml.snakeyaml.constructor.BaseConstructor; 31import org.yaml.snakeyaml.constructor.Constructor; 32import org.yaml.snakeyaml.emitter.Emitter; 33import org.yaml.snakeyaml.error.YAMLException; 34import org.yaml.snakeyaml.events.Event; 35import org.yaml.snakeyaml.introspector.BeanAccess; 36import org.yaml.snakeyaml.nodes.Node; 37import org.yaml.snakeyaml.nodes.Tag; 38import org.yaml.snakeyaml.parser.Parser; 39import org.yaml.snakeyaml.parser.ParserImpl; 40import org.yaml.snakeyaml.reader.StreamReader; 41import org.yaml.snakeyaml.reader.UnicodeReader; 42import org.yaml.snakeyaml.representer.Representer; 43import org.yaml.snakeyaml.resolver.Resolver; 44import org.yaml.snakeyaml.serializer.Serializer; 45 46/** 47 * Public YAML interface. Each Thread must have its own instance. 48 */ 49public class Yaml { 50 protected final Resolver resolver; 51 private String name; 52 protected BaseConstructor constructor; 53 protected Representer representer; 54 protected DumperOptions dumperOptions; 55 protected LoaderOptions loaderOptions; 56 57 /** 58 * Create Yaml instance. It is safe to create a few instances and use them 59 * in different Threads. 60 */ 61 public Yaml() { 62 this(new Constructor(), new LoaderOptions(), new Representer(), new DumperOptions(), 63 new Resolver()); 64 } 65 66 public Yaml(LoaderOptions loaderOptions) { 67 this(new Constructor(), loaderOptions, new Representer(), new DumperOptions(), 68 new Resolver()); 69 } 70 71 /** 72 * Create Yaml instance. 73 * 74 * @param dumperOptions 75 * DumperOptions to configure outgoing objects 76 */ 77 public Yaml(DumperOptions dumperOptions) { 78 this(new Constructor(), new Representer(), dumperOptions); 79 } 80 81 /** 82 * Create Yaml instance. It is safe to create a few instances and use them 83 * in different Threads. 84 * 85 * @param representer 86 * Representer to emit outgoing objects 87 */ 88 public Yaml(Representer representer) { 89 this(new Constructor(), representer); 90 } 91 92 /** 93 * Create Yaml instance. It is safe to create a few instances and use them 94 * in different Threads. 95 * 96 * @param constructor 97 * BaseConstructor to construct incoming documents 98 */ 99 public Yaml(BaseConstructor constructor) { 100 this(constructor, new Representer()); 101 } 102 103 /** 104 * Create Yaml instance. It is safe to create a few instances and use them 105 * in different Threads. 106 * 107 * @param constructor 108 * BaseConstructor to construct incoming documents 109 * @param representer 110 * Representer to emit outgoing objects 111 */ 112 public Yaml(BaseConstructor constructor, Representer representer) { 113 this(constructor, representer, new DumperOptions()); 114 } 115 116 /** 117 * Create Yaml instance. It is safe to create a few instances and use them 118 * in different Threads. 119 * 120 * @param representer 121 * Representer to emit outgoing objects 122 * @param dumperOptions 123 * DumperOptions to configure outgoing objects 124 */ 125 public Yaml(Representer representer, DumperOptions dumperOptions) { 126 this(new Constructor(), representer, dumperOptions, new Resolver()); 127 } 128 129 /** 130 * Create Yaml instance. It is safe to create a few instances and use them 131 * in different Threads. 132 * 133 * @param constructor 134 * BaseConstructor to construct incoming documents 135 * @param representer 136 * Representer to emit outgoing objects 137 * @param dumperOptions 138 * DumperOptions to configure outgoing objects 139 */ 140 public Yaml(BaseConstructor constructor, Representer representer, DumperOptions dumperOptions) { 141 this(constructor, representer, dumperOptions, new Resolver()); 142 } 143 144 /** 145 * Create Yaml instance. It is safe to create a few instances and use them 146 * in different Threads. 147 * 148 * @param constructor 149 * BaseConstructor to construct incoming documents 150 * @param representer 151 * Representer to emit outgoing objects 152 * @param dumperOptions 153 * DumperOptions to configure outgoing objects 154 * @param resolver 155 * Resolver to detect implicit type 156 */ 157 public Yaml(BaseConstructor constructor, Representer representer, DumperOptions dumperOptions, 158 Resolver resolver) { 159 this(constructor, new LoaderOptions(), representer, dumperOptions, resolver); 160 } 161 162 /** 163 * Create Yaml instance. It is safe to create a few instances and use them 164 * in different Threads. 165 * 166 * @param constructor 167 * BaseConstructor to construct incoming documents 168 * @param loaderOptions 169 * LoaderOptions to control construction process 170 * @param representer 171 * Representer to emit outgoing objects 172 * @param dumperOptions 173 * DumperOptions to configure outgoing objects 174 * @param resolver 175 * Resolver to detect implicit type 176 */ 177 public Yaml(BaseConstructor constructor, LoaderOptions loaderOptions, Representer representer, 178 DumperOptions dumperOptions, Resolver resolver) { 179 if (!constructor.isExplicitPropertyUtils()) { 180 constructor.setPropertyUtils(representer.getPropertyUtils()); 181 } else if (!representer.isExplicitPropertyUtils()) { 182 representer.setPropertyUtils(constructor.getPropertyUtils()); 183 } 184 this.constructor = constructor; 185 this.loaderOptions = loaderOptions; 186 representer.setDefaultFlowStyle(dumperOptions.getDefaultFlowStyle()); 187 representer.setDefaultScalarStyle(dumperOptions.getDefaultScalarStyle()); 188 representer.getPropertyUtils().setAllowReadOnlyProperties( 189 dumperOptions.isAllowReadOnlyProperties()); 190 this.representer = representer; 191 this.dumperOptions = dumperOptions; 192 this.resolver = resolver; 193 this.name = "Yaml:" + System.identityHashCode(this); 194 } 195 196 /** 197 * Serialize a Java object into a YAML String. 198 * 199 * @param data 200 * Java object to be Serialized to YAML 201 * @return YAML String 202 */ 203 public String dump(Object data) { 204 List<Object> list = new ArrayList<Object>(1); 205 list.add(data); 206 return dumpAll(list.iterator()); 207 } 208 209 /** 210 * Serialize a sequence of Java objects into a YAML String. 211 * 212 * @param data 213 * Iterator with Objects 214 * @return YAML String with all the objects in proper sequence 215 */ 216 public String dumpAll(Iterator<? extends Object> data) { 217 StringWriter buffer = new StringWriter(); 218 dumpAll(data, buffer); 219 return buffer.toString(); 220 } 221 222 /** 223 * Serialize a Java object into a YAML stream. 224 * 225 * @param data 226 * Java object to be Serialized to YAML 227 * @param output 228 * stream to write to 229 */ 230 public void dump(Object data, Writer output) { 231 List<Object> list = new ArrayList<Object>(1); 232 list.add(data); 233 dumpAll(list.iterator(), output); 234 } 235 236 /** 237 * Serialize a sequence of Java objects into a YAML stream. 238 * 239 * @param data 240 * Iterator with Objects 241 * @param output 242 * stream to write to 243 */ 244 public void dumpAll(Iterator<? extends Object> data, Writer output) { 245 Serializer s = new Serializer(new Emitter(output, dumperOptions), resolver, dumperOptions); 246 try { 247 s.open(); 248 while (data.hasNext()) { 249 representer.represent(s, data.next()); 250 } 251 s.close(); 252 } catch (java.io.IOException e) { 253 throw new YAMLException(e); 254 } 255 } 256 257 /** 258 * Parse the only YAML document in a String and produce the corresponding 259 * Java object. (Because the encoding in known BOM is not respected.) 260 * 261 * @param yaml 262 * YAML data to load from (BOM must not be present) 263 * @return parsed object 264 */ 265 public Object load(String yaml) { 266 return load(new StringReader(yaml)); 267 } 268 269 /** 270 * Parse the only YAML document in a stream and produce the corresponding 271 * Java object. 272 * 273 * @param io 274 * data to load from (BOM is respected and removed) 275 * @return parsed object 276 */ 277 public Object load(InputStream io) { 278 return load(new UnicodeReader(io)); 279 } 280 281 /** 282 * Parse the only YAML document in a stream and produce the corresponding 283 * Java object. 284 * 285 * @param io 286 * data to load from (BOM must not be present) 287 * @return parsed object 288 */ 289 public Object load(Reader io) { 290 Composer composer = new Composer(new ParserImpl(new StreamReader(io, loaderOptions 291 .isWithMarkContext())), resolver); 292 constructor.setComposer(composer); 293 return constructor.getSingleData(); 294 } 295 296 /** 297 * Parse all YAML documents in a String and produce corresponding Java 298 * objects. The documents are parsed only when the iterator is invoked. 299 * 300 * @param yaml 301 * YAML data to load from (BOM must not be present) 302 * @return an iterator over the parsed Java objects in this String in proper 303 * sequence 304 */ 305 public Iterable<Object> loadAll(Reader yaml) { 306 Composer composer = new Composer(new ParserImpl(new StreamReader(yaml, loaderOptions 307 .isWithMarkContext())), resolver); 308 constructor.setComposer(composer); 309 Iterator<Object> result = new Iterator<Object>() { 310 public boolean hasNext() { 311 return constructor.checkData(); 312 } 313 314 public Object next() { 315 return constructor.getData(); 316 } 317 318 public void remove() { 319 throw new UnsupportedOperationException(); 320 } 321 }; 322 return new YamlIterable(result); 323 } 324 325 private class YamlIterable implements Iterable<Object> { 326 private Iterator<Object> iterator; 327 328 public YamlIterable(Iterator<Object> iterator) { 329 this.iterator = iterator; 330 } 331 332 public Iterator<Object> iterator() { 333 return iterator; 334 } 335 336 } 337 338 /** 339 * Parse all YAML documents in a String and produce corresponding Java 340 * objects. (Because the encoding in known BOM is not respected.) The 341 * documents are parsed only when the iterator is invoked. 342 * 343 * @param yaml 344 * YAML data to load from (BOM must not be present) 345 * @return an iterator over the parsed Java objects in this String in proper 346 * sequence 347 */ 348 public Iterable<Object> loadAll(String yaml) { 349 return loadAll(new StringReader(yaml)); 350 } 351 352 /** 353 * Parse all YAML documents in a stream and produce corresponding Java 354 * objects. The documents are parsed only when the iterator is invoked. 355 * 356 * @param yaml 357 * YAML data to load from (BOM is respected and ignored) 358 * @return an iterator over the parsed Java objects in this stream in proper 359 * sequence 360 */ 361 public Iterable<Object> loadAll(InputStream yaml) { 362 return loadAll(new UnicodeReader(yaml)); 363 } 364 365 /** 366 * Parse the first YAML document in a stream and produce the corresponding 367 * representation tree. 368 * 369 * @param yaml 370 * YAML document 371 * @return parsed root Node for the specified YAML document 372 */ 373 public Node compose(Reader yaml) { 374 Composer composer = new Composer(new ParserImpl(new StreamReader(yaml, loaderOptions 375 .isWithMarkContext())), resolver); 376 constructor.setComposer(composer); 377 return composer.getSingleNode(); 378 } 379 380 /** 381 * Parse all YAML documents in a stream and produce corresponding 382 * representation trees. 383 * 384 * @param yaml 385 * stream of YAML documents 386 * @return parsed root Nodes for all the specified YAML documents 387 */ 388 public Iterable<Node> composeAll(Reader yaml) { 389 final Composer composer = new Composer(new ParserImpl(new StreamReader(yaml, loaderOptions 390 .isWithMarkContext())), resolver); 391 constructor.setComposer(composer); 392 Iterator<Node> result = new Iterator<Node>() { 393 public boolean hasNext() { 394 return composer.checkNode(); 395 } 396 397 public Node next() { 398 return composer.getNode(); 399 } 400 401 public void remove() { 402 throw new UnsupportedOperationException(); 403 } 404 }; 405 return new NodeIterable(result); 406 } 407 408 private class NodeIterable implements Iterable<Node> { 409 private Iterator<Node> iterator; 410 411 public NodeIterable(Iterator<Node> iterator) { 412 this.iterator = iterator; 413 } 414 415 public Iterator<Node> iterator() { 416 return iterator; 417 } 418 } 419 420 /** 421 * Add an implicit scalar detector. If an implicit scalar value matches the 422 * given regexp, the corresponding tag is assigned to the scalar. 423 * 424 * @deprecated use Tag instead of String 425 * @param tag 426 * tag to assign to the node 427 * @param regexp 428 * regular expression to match against 429 * @param first 430 * a sequence of possible initial characters or null (which means 431 * any). 432 * 433 */ 434 public void addImplicitResolver(String tag, Pattern regexp, String first) { 435 addImplicitResolver(new Tag(tag), regexp, first); 436 } 437 438 /** 439 * Add an implicit scalar detector. If an implicit scalar value matches the 440 * given regexp, the corresponding tag is assigned to the scalar. 441 * 442 * @param tag 443 * tag to assign to the node 444 * @param regexp 445 * regular expression to match against 446 * @param first 447 * a sequence of possible initial characters or null (which means 448 * any). 449 */ 450 public void addImplicitResolver(Tag tag, Pattern regexp, String first) { 451 resolver.addImplicitResolver(tag, regexp, first); 452 } 453 454 @Override 455 public String toString() { 456 return name; 457 } 458 459 /** 460 * Get a meaningful name. It simplifies debugging in a multi-threaded 461 * environment. If nothing is set explicitly the address of the instance is 462 * returned. 463 * 464 * @return human readable name 465 */ 466 public String getName() { 467 return name; 468 } 469 470 /** 471 * Set a meaningful name to be shown in toString() 472 * 473 * @param name 474 * human readable name 475 */ 476 public void setName(String name) { 477 this.name = name; 478 } 479 480 /** 481 * Parse a YAML stream and produce parsing events. 482 * 483 * @param yaml 484 * YAML document(s) 485 * @return parsed events 486 */ 487 public Iterable<Event> parse(Reader yaml) { 488 final Parser parser = new ParserImpl(new StreamReader(yaml, loaderOptions 489 .isWithMarkContext())); 490 Iterator<Event> result = new Iterator<Event>() { 491 public boolean hasNext() { 492 return parser.peekEvent() != null; 493 } 494 495 public Event next() { 496 return parser.getEvent(); 497 } 498 499 public void remove() { 500 throw new UnsupportedOperationException(); 501 } 502 }; 503 return new EventIterable(result); 504 } 505 506 private class EventIterable implements Iterable<Event> { 507 private Iterator<Event> iterator; 508 509 public EventIterable(Iterator<Event> iterator) { 510 this.iterator = iterator; 511 } 512 513 public Iterator<Event> iterator() { 514 return iterator; 515 } 516 } 517 518 public void setBeanAccess(BeanAccess beanAccess) { 519 constructor.getPropertyUtils().setBeanAccess(beanAccess); 520 representer.getPropertyUtils().setBeanAccess(beanAccess); 521 } 522 523 // deprecated 524 /** 525 * @deprecated use with Constructor instead of Loader 526 */ 527 public Yaml(Loader loader) { 528 this(loader, new Dumper(new DumperOptions())); 529 } 530 531 /** 532 * @deprecated use with Constructor instead of Loader 533 */ 534 public Yaml(Loader loader, Dumper dumper) { 535 this(loader, dumper, new Resolver()); 536 } 537 538 /** 539 * @deprecated use with Constructor instead of Loader 540 */ 541 public Yaml(Loader loader, Dumper dumper, Resolver resolver) { 542 this(loader.constructor, dumper.representer, dumper.options, resolver); 543 } 544 545 /** 546 * Create Yaml instance. It is safe to create a few instances and use them 547 * in different Threads. 548 * 549 * @param dumper 550 * Dumper to emit outgoing objects 551 */ 552 @SuppressWarnings("deprecation") 553 public Yaml(Dumper dumper) { 554 this(new Constructor(), dumper.representer, dumper.options); 555 } 556} 557