vendor snakeyaml

we can't use shade-maven-plugin directly being incompatible with incremental versionning

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2018-09-11 14:40:01 +02:00 committed by Nicolas De loof
parent 4d8d3540b0
commit 9d837317eb
119 changed files with 17326 additions and 604 deletions

1
.gitignore vendored
View File

@ -2,7 +2,6 @@ target/
work/
.idea/
*.iml
snakeyaml/src
# ignore jenkins.yaml from root folder (used by many for testing)
/jenkins.yaml

3
snakeyaml/README.md Normal file
View File

@ -0,0 +1,3 @@
This is a vendored version of snakeyaml library.
To upgrade, change `snakeyaml.version` and run `mvn -Pvendor package`

View File

@ -1,538 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>parent</artifactId>
<groupId>io.jenkins.configuration-as-code</groupId>
<version>${revision}${changelist}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>snakeyaml</artifactId>
<description>Snakeyaml shaded for configuration-as-code plugin</description>
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>shade</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<createSourcesJar>true</createSourcesJar>
<shadeSourcesContent>true</shadeSourcesContent>
<artifactSet>
<includes>
<include>org.yaml*:*</include>
</includes>
</artifactSet>
<relocations>
<relocation>
<pattern>org.yaml.snakeyaml</pattern>
<shadedPattern>io.jenkins.plugins.casc.snakeyaml</shadedPattern>
</relocation>
</relocations>
</configuration>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<classifier>sources</classifier>
<type>jar</type>
<outputDirectory>${basedir}/src/main/java</outputDirectory>
<includes>**/**</includes>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>annotations</artifactId>
<version>3.0.0</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.jcip</groupId>
<artifactId>jcip-annotations</artifactId>
<version>1.0</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-annotations</artifactId>
<version>1.17</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>jenkins-core</artifactId>
<version>2.60.3</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<artifactId>icon-set</artifactId>
<groupId>org.jenkins-ci.plugins.icon-shim</groupId>
</exclusion>
<exclusion>
<artifactId>remoting</artifactId>
<groupId>org.jenkins-ci.main</groupId>
</exclusion>
<exclusion>
<artifactId>cli</artifactId>
<groupId>org.jenkins-ci.main</groupId>
</exclusion>
<exclusion>
<artifactId>version-number</artifactId>
<groupId>org.jenkins-ci</groupId>
</exclusion>
<exclusion>
<artifactId>crypto-util</artifactId>
<groupId>org.jenkins-ci</groupId>
</exclusion>
<exclusion>
<artifactId>jtidy</artifactId>
<groupId>org.jvnet.hudson</groupId>
</exclusion>
<exclusion>
<artifactId>guice</artifactId>
<groupId>com.google.inject</groupId>
</exclusion>
<exclusion>
<artifactId>jna-posix</artifactId>
<groupId>org.jruby.ext.posix</groupId>
</exclusion>
<exclusion>
<artifactId>jnr-posix</artifactId>
<groupId>com.github.jnr</groupId>
</exclusion>
<exclusion>
<artifactId>trilead-putty-extension</artifactId>
<groupId>org.kohsuke</groupId>
</exclusion>
<exclusion>
<artifactId>trilead-ssh2</artifactId>
<groupId>org.jenkins-ci</groupId>
</exclusion>
<exclusion>
<artifactId>stapler-groovy</artifactId>
<groupId>org.kohsuke.stapler</groupId>
</exclusion>
<exclusion>
<artifactId>stapler-jrebel</artifactId>
<groupId>org.kohsuke.stapler</groupId>
</exclusion>
<exclusion>
<artifactId>windows-package-checker</artifactId>
<groupId>org.kohsuke</groupId>
</exclusion>
<exclusion>
<artifactId>stapler-adjunct-zeroclipboard</artifactId>
<groupId>org.kohsuke.stapler</groupId>
</exclusion>
<exclusion>
<artifactId>stapler-adjunct-timeline</artifactId>
<groupId>org.kohsuke.stapler</groupId>
</exclusion>
<exclusion>
<artifactId>stapler-adjunct-codemirror</artifactId>
<groupId>org.kohsuke.stapler</groupId>
</exclusion>
<exclusion>
<artifactId>bridge-method-annotation</artifactId>
<groupId>com.infradna.tool</groupId>
</exclusion>
<exclusion>
<artifactId>json-lib</artifactId>
<groupId>org.kohsuke.stapler</groupId>
</exclusion>
<exclusion>
<artifactId>commons-httpclient</artifactId>
<groupId>commons-httpclient</groupId>
</exclusion>
<exclusion>
<artifactId>args4j</artifactId>
<groupId>args4j</groupId>
</exclusion>
<exclusion>
<artifactId>annotation-indexer</artifactId>
<groupId>org.jenkins-ci</groupId>
</exclusion>
<exclusion>
<artifactId>bytecode-compatibility-transformer</artifactId>
<groupId>org.jenkins-ci</groupId>
</exclusion>
<exclusion>
<artifactId>task-reactor</artifactId>
<groupId>org.jenkins-ci</groupId>
</exclusion>
<exclusion>
<artifactId>localizer</artifactId>
<groupId>org.jvnet.localizer</groupId>
</exclusion>
<exclusion>
<artifactId>antlr</artifactId>
<groupId>antlr</groupId>
</exclusion>
<exclusion>
<artifactId>xstream</artifactId>
<groupId>org.jvnet.hudson</groupId>
</exclusion>
<exclusion>
<artifactId>jfreechart</artifactId>
<groupId>jfree</groupId>
</exclusion>
<exclusion>
<artifactId>ant</artifactId>
<groupId>org.apache.ant</groupId>
</exclusion>
<exclusion>
<artifactId>commons-io</artifactId>
<groupId>commons-io</groupId>
</exclusion>
<exclusion>
<artifactId>commons-lang</artifactId>
<groupId>commons-lang</groupId>
</exclusion>
<exclusion>
<artifactId>commons-digester</artifactId>
<groupId>commons-digester</groupId>
</exclusion>
<exclusion>
<artifactId>commons-beanutils</artifactId>
<groupId>commons-beanutils</groupId>
</exclusion>
<exclusion>
<artifactId>commons-compress</artifactId>
<groupId>org.apache.commons</groupId>
</exclusion>
<exclusion>
<artifactId>mail</artifactId>
<groupId>javax.mail</groupId>
</exclusion>
<exclusion>
<artifactId>activation</artifactId>
<groupId>org.jvnet.hudson</groupId>
</exclusion>
<exclusion>
<artifactId>jaxen</artifactId>
<groupId>jaxen</groupId>
</exclusion>
<exclusion>
<artifactId>commons-jelly-tags-fmt</artifactId>
<groupId>commons-jelly</groupId>
</exclusion>
<exclusion>
<artifactId>commons-jelly-tags-xml</artifactId>
<groupId>commons-jelly</groupId>
</exclusion>
<exclusion>
<artifactId>commons-jelly-tags-define</artifactId>
<groupId>org.jvnet.hudson</groupId>
</exclusion>
<exclusion>
<artifactId>commons-jexl</artifactId>
<groupId>org.jenkins-ci</groupId>
</exclusion>
<exclusion>
<artifactId>acegi-security</artifactId>
<groupId>org.acegisecurity</groupId>
</exclusion>
<exclusion>
<artifactId>groovy-all</artifactId>
<groupId>org.codehaus.groovy</groupId>
</exclusion>
<exclusion>
<artifactId>jline</artifactId>
<groupId>jline</groupId>
</exclusion>
<exclusion>
<artifactId>jansi</artifactId>
<groupId>org.fusesource.jansi</groupId>
</exclusion>
<exclusion>
<artifactId>spring-webmvc</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-core</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-aop</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>xpp3</artifactId>
<groupId>xpp3</groupId>
</exclusion>
<exclusion>
<artifactId>jstl</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
<exclusion>
<artifactId>txw2</artifactId>
<groupId>com.sun.xml.txw2</groupId>
</exclusion>
<exclusion>
<artifactId>commons-collections</artifactId>
<groupId>commons-collections</groupId>
</exclusion>
<exclusion>
<artifactId>winp</artifactId>
<groupId>org.jvnet.winp</groupId>
</exclusion>
<exclusion>
<artifactId>memory-monitor</artifactId>
<groupId>org.jenkins-ci</groupId>
</exclusion>
<exclusion>
<artifactId>wstx-asl</artifactId>
<groupId>org.codehaus.woodstox</groupId>
</exclusion>
<exclusion>
<artifactId>jmdns</artifactId>
<groupId>org.jenkins-ci</groupId>
</exclusion>
<exclusion>
<artifactId>jna</artifactId>
<groupId>net.java.dev.jna</groupId>
</exclusion>
<exclusion>
<artifactId>akuma</artifactId>
<groupId>org.kohsuke</groupId>
</exclusion>
<exclusion>
<artifactId>libpam4j</artifactId>
<groupId>org.kohsuke</groupId>
</exclusion>
<exclusion>
<artifactId>libzfs</artifactId>
<groupId>org.kohsuke</groupId>
</exclusion>
<exclusion>
<artifactId>embedded_su4j</artifactId>
<groupId>com.sun.solaris</groupId>
</exclusion>
<exclusion>
<artifactId>sezpoz</artifactId>
<groupId>net.java.sezpoz</groupId>
</exclusion>
<exclusion>
<artifactId>j-interop</artifactId>
<groupId>org.kohsuke.jinterop</groupId>
</exclusion>
<exclusion>
<artifactId>robust-http-client</artifactId>
<groupId>org.jvnet.robust-http-client</groupId>
</exclusion>
<exclusion>
<artifactId>symbol-annotation</artifactId>
<groupId>org.jenkins-ci</groupId>
</exclusion>
<exclusion>
<artifactId>commons-codec</artifactId>
<groupId>commons-codec</groupId>
</exclusion>
<exclusion>
<artifactId>commons-fileupload</artifactId>
<groupId>commons-fileupload</groupId>
</exclusion>
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
<exclusion>
<artifactId>jzlib</artifactId>
<groupId>com.jcraft</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>jenkins-war</artifactId>
<version>2.60.3</version>
<type>executable-war</type>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>instance-identity</artifactId>
<groupId>org.jenkins-ci.modules</groupId>
</exclusion>
<exclusion>
<artifactId>ssh-cli-auth</artifactId>
<groupId>org.jenkins-ci.modules</groupId>
</exclusion>
<exclusion>
<artifactId>slave-installer</artifactId>
<groupId>org.jenkins-ci.modules</groupId>
</exclusion>
<exclusion>
<artifactId>windows-slave-installer</artifactId>
<groupId>org.jenkins-ci.modules</groupId>
</exclusion>
<exclusion>
<artifactId>launchd-slave-installer</artifactId>
<groupId>org.jenkins-ci.modules</groupId>
</exclusion>
<exclusion>
<artifactId>upstart-slave-installer</artifactId>
<groupId>org.jenkins-ci.modules</groupId>
</exclusion>
<exclusion>
<artifactId>systemd-slave-installer</artifactId>
<groupId>org.jenkins-ci.modules</groupId>
</exclusion>
<exclusion>
<artifactId>sshd</artifactId>
<groupId>org.jenkins-ci.modules</groupId>
</exclusion>
<exclusion>
<artifactId>jquery-detached</artifactId>
<groupId>org.jenkins-ci.ui</groupId>
</exclusion>
<exclusion>
<artifactId>bootstrap</artifactId>
<groupId>org.jenkins-ci.ui</groupId>
</exclusion>
<exclusion>
<artifactId>handlebars</artifactId>
<groupId>org.jenkins-ci.ui</groupId>
</exclusion>
<exclusion>
<artifactId>remoting</artifactId>
<groupId>org.jenkins-ci.main</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>jenkins-test-harness</artifactId>
<version>2.38</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>junit-dep</artifactId>
<groupId>junit</groupId>
</exclusion>
<exclusion>
<artifactId>jetty-webapp</artifactId>
<groupId>org.eclipse.jetty</groupId>
</exclusion>
<exclusion>
<artifactId>jetty-security</artifactId>
<groupId>org.eclipse.jetty</groupId>
</exclusion>
<exclusion>
<artifactId>hamcrest-library</artifactId>
<groupId>org.hamcrest</groupId>
</exclusion>
<exclusion>
<artifactId>jenkins-test-harness-htmlunit</artifactId>
<groupId>org.jenkins-ci.main</groupId>
</exclusion>
<exclusion>
<artifactId>embedded-rhino-debugger</artifactId>
<groupId>org.jvnet.hudson</groupId>
</exclusion>
<exclusion>
<artifactId>org-netbeans-insane</artifactId>
<groupId>org.netbeans.modules</groupId>
</exclusion>
<exclusion>
<artifactId>findbugs-annotations</artifactId>
<groupId>com.github.stephenc.findbugs</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jenkins-ci</groupId>
<artifactId>test-annotations</artifactId>
<version>1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>hamcrest-core</artifactId>
<groupId>org.hamcrest</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.25</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.25</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.25</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.kohsuke</groupId>
<artifactId>access-modifier-annotation</artifactId>
<version>1.15</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<artifactId>annotation-indexer</artifactId>
<groupId>org.jenkins-ci</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<properties>
<findbugs.skip>true</findbugs.skip>
<maven.source.skip>true</maven.source.skip>
</properties>
</project>

View File

@ -11,76 +11,92 @@
<description>Snakeyaml shaded for configuration-as-code plugin</description>
<properties>
<maven.source.skip>true</maven.source.skip>
<findbugs.skip>true</findbugs.skip>
<maven.javadoc.skip>true</maven.javadoc.skip>
<snakeyaml.version>1.23</snakeyaml.version>
</properties>
<dependencies>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.23</version>
<scope>compile</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>vendor</id>
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>shade</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<createSourcesJar>true</createSourcesJar>
<shadeSourcesContent>true</shadeSourcesContent>
<artifactSet>
<includes>
<include>org.yaml*:*</include>
</includes>
</artifactSet>
<relocations>
<relocation>
<pattern>org.yaml.snakeyaml</pattern>
<shadedPattern>io.jenkins.plugins.casc.snakeyaml</shadedPattern>
</relocation>
</relocations>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>package</phase>
<goals>
<goal>unpack</goal>
</goals>
<dependencies>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${snakeyaml.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<configuration>
<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<classifier>sources</classifier>
<type>jar</type>
<outputDirectory>${basedir}/src/main/java</outputDirectory>
<includes>**/**</includes>
</artifactItem>
</artifactItems>
<directory>${basedir}/src</directory>
</configuration>
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>shade</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<createSourcesJar>true</createSourcesJar>
<shadeSourcesContent>true</shadeSourcesContent>
<createDependencyReducedPom>false</createDependencyReducedPom>
<artifactSet>
<includes>
<include>org.yaml*:*</include>
</includes>
</artifactSet>
<relocations>
<relocation>
<pattern>org.yaml.snakeyaml</pattern>
<shadedPattern>io.jenkins.plugins.casc.snakeyaml</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<classifier>sources</classifier>
<type>jar</type>
<outputDirectory>${basedir}/src/main/java</outputDirectory>
<includes>**/**</includes>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,5 @@
Manifest-Version: 1.0
Built-By: somov
Created-By: Apache Maven 3.5.3
Build-Jdk: 1.8.0_181

View File

@ -0,0 +1,4 @@
#Created by Apache Maven 3.5.3
version=1.23
groupId=org.yaml
artifactId=snakeyaml

View File

@ -0,0 +1,833 @@
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.23</version>
<packaging>bundle</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.scm.id>bitbucket</project.scm.id>
<release.repo.url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</release.repo.url>
<snapshot.repo.url>https://oss.sonatype.org/content/repositories/snapshots/</snapshot.repo.url>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
<maven.javadoc.failOnError>false</maven.javadoc.failOnError>
<spring.version>3.2.17.RELEASE</spring.version>
<maven-bundle-plugin.version>3.5.0</maven-bundle-plugin.version>
<cobertura-maven-plugin.version>2.7</cobertura-maven-plugin.version>
<maven-site-plugin.version>3.6</maven-site-plugin.version>
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
<jdk9-illegal-access-level>deny</jdk9-illegal-access-level>
</properties>
<name>SnakeYAML</name>
<description>YAML 1.1 parser and emitter for Java</description>
<inceptionYear>2008</inceptionYear>
<url>http://www.snakeyaml.org</url>
<issueManagement>
<system>Bitbucket</system>
<url>https://bitbucket.org/asomov/snakeyaml/issues</url>
</issueManagement>
<!--ciManagement>
<system>jenkins</system>
<url>https://snakeyaml.ci.cloudbees.com/job/SnakeYAML/</url>
</ciManagement-->
<mailingLists>
<mailingList>
<name>SnakeYAML developers and users List</name>
<post>snakeyaml-core@googlegroups.com</post>
</mailingList>
</mailingLists>
<scm>
<connection>scm:hg:http://bitbucket.org/asomov/snakeyaml</connection>
<developerConnection>scm:hg:ssh://hg@bitbucket.org/asomov/snakeyaml</developerConnection>
<url>https://bitbucket.org/asomov/snakeyaml/src</url>
<tag>snakeyaml-1.23</tag>
</scm>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>asomov</id>
<name>Andrey Somov</name>
<email>public.somov@gmail.com</email>
</developer>
<developer>
<id>maslovalex</id>
<name>Alexander Maslov</name>
<email>alexander.maslov@gmail.com</email>
</developer>
<developer>
<id>Jordan</id>
<name>Jordan Angold</name>
<email>jordanangold@gmail.com</email>
</developer>
</developers>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>1.6</version>
<scope>test</scope>
</dependency>
</dependencies>
<distributionManagement>
<repository>
<id>sonatype-nexus-staging</id>
<name>Nexus Release Repository</name>
<url>${release.repo.url}</url>
</repository>
<snapshotRepository>
<id>sonatype-nexus-staging</id>
<name>Sonatype Nexus Snapshots</name>
<url>${snapshot.repo.url}</url>
<uniqueVersion>false</uniqueVersion>
</snapshotRepository>
</distributionManagement>
<build>
<testResources>
<testResource>
<directory>${basedir}/src/test/resources</directory>
<filtering>true</filtering>
</testResource>
</testResources>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
<configuration>
<excludePackageNames>org.yaml.snakeyaml.external.*</excludePackageNames>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>${maven-site-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>${cobertura-maven-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.12</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.4.1</version>
<executions>
<execution>
<id>enforce-maven</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireMavenVersion>
<version>3.0.5</version>
</requireMavenVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Xmx512m</argLine>
<includes>
<include>**/*Test.java</include>
</includes>
<excludes>
<exclude>**/StressTest.java</exclude>
<exclude>**/ParallelTest.java</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.10</version>
<configuration>
<buildOutputDirectory>bin</buildOutputDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-changes-plugin</artifactId>
<version>2.12.1</version>
<executions>
<execution>
<id>validate-changes</id>
<phase>pre-site</phase>
<goals>
<goal>changes-validate</goal>
</goals>
<configuration>
<failOnError>true</failOnError>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<links>
<link>https://docs.oracle.com/javase/6/docs/api/</link>
</links>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.mycila.maven-license-plugin</groupId>
<artifactId>maven-license-plugin</artifactId>
<version>1.10.b1</version>
<configuration>
<header>src/etc/header.txt</header>
<quiet>false</quiet>
<failIfMissing>true</failIfMissing>
<aggregate>false</aggregate>
<includes>
<include>src/**/*.java</include>
</includes>
<excludes>
<exclude>src/main/java/org/yaml/snakeyaml/external/**</exclude>
</excludes>
<useDefaultExcludes>true</useDefaultExcludes>
<useDefaultMapping>true</useDefaultMapping>
<strictCheck>true</strictCheck>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<phase>site</phase>
<goals>
<goal>format</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>${maven-bundle-plugin.version}</version>
<extensions>true</extensions>
<configuration>
<instructions>
<_nouses>true</_nouses>
<Export-Package>
!org.yaml.snakeyaml.external*,
org.yaml.snakeyaml.*;version=${project.version}
</Export-Package>
</instructions>
</configuration>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>${maven-site-plugin.version}</version>
<executions>
<execution>
<id>attach-descriptor</id>
<goals>
<goal>attach-descriptor</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<autoVersionSubmodules>true</autoVersionSubmodules>
<useReleaseProfile>false</useReleaseProfile>
<releaseProfiles>android,release</releaseProfiles>
<goals>deploy nexus-staging:release</goals>
</configuration>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.7</version>
<extensions>true</extensions>
<configuration>
<serverId>sonatype-nexus-staging</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>false</autoReleaseAfterClose>
</configuration>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-changes-plugin</artifactId>
<version>2.11</version>
<configuration>
<issueLinkTemplate>https://bitbucket.org/asomov/snakeyaml/issues/%ISSUE%</issueLinkTemplate>
</configuration>
<reportSets>
<reportSet>
<reports>
<report>changes-report</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<showSuccess>true</showSuccess>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<reportSets>
<reportSet>
<id>html</id>
<configuration>
<doctitle>API for ${project.name} ${project.version}</doctitle>
<windowtitle>API for ${project.name} ${project.version}</windowtitle>
<testDoctitle>Test API for ${project.name} ${project.version}</testDoctitle>
<testWindowtitle>Test API for ${project.name} ${project.version}</testWindowtitle>
</configuration>
<reports>
<report>javadoc</report>
</reports>
</reportSet>
</reportSets>
</plugin>
</plugins>
</reporting>
<profiles>
<profile>
<id>toolchain</id>
<activation>
<file>
<exists>${user.home}/.m2/toolchains.xml</exists>
</file>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-toolchains-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>toolchain</goal>
</goals>
</execution>
</executions>
<configuration>
<toolchains>
<jdk>
<version>${maven.compiler.target}</version>
</jdk>
</toolchains>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>build-is-under-jdk6</id>
<activation>
<jdk>1.6</jdk>
</activation>
<properties>
<maven-bundle-plugin.version>2.5.4</maven-bundle-plugin.version>
</properties>
</profile>
<profile>
<id>with-coverage</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<configuration>
<check>
<totalBranchRate>80</totalBranchRate>
<totalLineRate>95</totalLineRate>
</check>
<formats>
<format>html</format>
<format>xml</format>
</formats>
<instrumentation>
<excludes>
<exclude>org/yaml/snakeyaml/external/**</exclude>
</excludes>
</instrumentation>
</configuration>
<executions>
<execution>
<goals>
<goal>clean</goal>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<configuration>
<check>
<branchRate>85</branchRate>
<lineRate>85</lineRate>
<haltOnFailure>true</haltOnFailure>
</check>
<formats>
<format>html</format>
<format>xml</format>
</formats>
</configuration>
<reportSets>
<reportSet>
<reports>
<report>cobertura</report>
</reports>
</reportSet>
</reportSets>
</plugin>
</plugins>
</reporting>
</profile>
<profile>
<id>with-java8-tests</id>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-java8-test-source</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>${basedir}/src/test/java7/</source>
<source>${basedir}/src/test/java8/</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>with-java11-tests</id>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>--illegal-access=${jdk9-illegal-access-level} -Xmx512m</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<!-- arg>-Xlint:unchecked</arg -->
<arg>-Xlint:deprecation</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-java11-test-source</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>${basedir}/src/test/java7/</source>
<source>${basedir}/src/test/java8/</source>
<source>${basedir}/src/test/java11/</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>release</id>
<activation>
<property>
<name>performRelease</name>
<value>true</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>findbugs</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.4</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.7</version>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>2.5</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.4</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.6</version>
<configuration>
<linkXref>true</linkXref>
<sourceEncoding>utf-8</sourceEncoding>
<minimumTokens>100</minimumTokens>
<targetJdk>1.5</targetJdk>
<excludes>
<exclude>**/external/*.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</reporting>
</profile>
<profile>
<id>android</id>
<properties>
<android.src>${project.build.directory}/android/src</android.src>
<android.src.main>${android.src}/main/java</android.src.main>
<android.src.test>${android.src}/test/java</android.src.test>
<android.classes>${project.build.directory}/android/classes/</android.classes>
<android.test.classes>${project.build.directory}/android/test-classes/</android.test.classes>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<id>copy-src-for-android</id>
<phase>generate-sources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${android.src.main}</outputDirectory>
<resources>
<resource>
<directory>${basedir}/src/main/java</directory>
<filtering>false</filtering>
<excludes>
<exclude>org/yaml/snakeyaml/introspector/MethodProperty.java</exclude>
</excludes>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-test-src-for-android</id>
<phase>generate-sources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${android.src.test}</outputDirectory>
<resources>
<resource>
<directory>${basedir}/src/test/java</directory>
<filtering>false</filtering>
<excludes>
<exclude>org/yaml/snakeyaml/introspector/MethodProperty.java</exclude>
</excludes>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-test-resources-for-android</id>
<phase>process-test-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${android.test.classes}</outputDirectory>
<resources>
<resource>
<directory>${basedir}/src/test/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-patch-plugin</artifactId>
<version>1.2</version>
<configuration>
<patchDirectory>${basedir}/src/patches/android/</patchDirectory>
<targetDirectory>${android.src}</targetDirectory>
<skipApplication>false</skipApplication>
<strip>2</strip>
</configuration>
<executions>
<execution>
<id>android-patches</id>
<phase>process-sources</phase>
<goals>
<goal>apply</goal>
</goals>
<configuration>
<patchTrackingFile>${project.build.directory}/android/patches-applied.txt</patchTrackingFile>
<naturalOrderProcessing>true</naturalOrderProcessing>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>build-for-android</id>
<phase>compile</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<mkdir dir="${android.classes}" />
<mkdir dir="${android.test.classes}" />
<!-- compile patched sources -->
<javac srcdir="${android.src.main}" destdir="${android.classes}" classpath="${android.classes}" encoding="${project.build.sourceEncoding}" target="1.6" source="1.6" debug="true" includeantruntime="false" fork="true" />
<!-- compile test classes. Exclude some - not for BeanAccess.FIELD -->
<javac srcdir="${android.src.test}:${basedir}/src/test/resources" destdir="${android.test.classes}" classpath="${android.classes}:${android.test.classes}:${junit:junit:jar}:${org.springframework:spring-core:jar}:${org.springframework:spring-beans:jar}:${org.springframework:spring-context:jar}:${org.apache.velocity:velocity:jar}:${joda-time:joda-time:jar}:${commons-io:commons-io:jar}:${commons-lang:commons-lang:jar}:${org.hamcrest:hamcrest-core:jar}" encoding="${project.build.sourceEncoding}" target="1.6" source="1.6" debug="true" includeantruntime="false" fork="true">
<exclude name="org/yaml/snakeyaml/introspector/MethodPropertyTest.java" />
<exclude name="org/yaml/snakeyaml/representer/FilterPropertyToDumpTest.java" />
<exclude name="org/yaml/snakeyaml/issues/issue60/CustomOrderTest.java" />
<exclude name="org/yaml/snakeyaml/issues/issue29/FlexibleScalarStylesInJavaBeanTest.java" />
<!-- uses filtered resources. Addidional tricks needed to be able to run under current build -->
<exclude name="org/yaml/snakeyaml/issues/issue318/ContextClassLoaderTest.java" />
</javac>
</target>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>test-android</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<classesDirectory>${android.classes}</classesDirectory>
<reportsDirectory>${project.build.directory}/android/surefire-reports
</reportsDirectory>
<testClassesDirectory>${android.test.classes}</testClassesDirectory>
<!--
We ignore test failures for android build at the moment.
Most of the FAILs are because of testing with "property" not "field" access.
But we still fail whole build if there are test errors.
-->
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>package-android-jar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classesDirectory>${android.classes}</classesDirectory>
<classifier>android</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,418 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml;
import java.util.Map;
import java.util.TimeZone;
import io.jenkins.plugins.casc.snakeyaml.emitter.Emitter;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
import io.jenkins.plugins.casc.snakeyaml.serializer.AnchorGenerator;
import io.jenkins.plugins.casc.snakeyaml.serializer.NumberAnchorGenerator;
public class DumperOptions {
/**
* YAML provides a rich set of scalar styles. Block scalar styles include
* the literal style and the folded style; flow scalar styles include the
* plain style and two quoted styles, the single-quoted style and the
* double-quoted style. These styles offer a range of trade-offs between
* expressive power and readability.
*
* @see <a href="http://yaml.org/spec/1.1/#id903915">Chapter 9. Scalar
* Styles</a>
* @see <a href="http://yaml.org/spec/1.1/#id858081">2.3. Scalars</a>
*/
public enum ScalarStyle {
DOUBLE_QUOTED('"'), SINGLE_QUOTED('\''), LITERAL(
'|'), FOLDED('>'), PLAIN(null);
private Character styleChar;
private ScalarStyle(Character style) {
this.styleChar = style;
}
public Character getChar() {
return styleChar;
}
@Override
public String toString() {
return "Scalar style: '" + styleChar + "'";
}
public static ScalarStyle createStyle(Character style) {
if (style == null) {
return PLAIN;
} else {
switch (style) {
case '"':
return DOUBLE_QUOTED;
case '\'':
return SINGLE_QUOTED;
case '|':
return LITERAL;
case '>':
return FOLDED;
default:
throw new YAMLException("Unknown scalar style character: " + style);
}
}
}
}
/**
* Block styles use indentation to denote nesting and scope within the
* document. In contrast, flow styles rely on explicit indicators to denote
* nesting and scope.
*
* @see <a href="http://www.yaml.org/spec/current.html#id2509255">3.2.3.1.
* Node Styles (http://yaml.org/spec/1.1)</a>
*/
public enum FlowStyle {
FLOW(Boolean.TRUE), BLOCK(Boolean.FALSE), AUTO(null);
private Boolean styleBoolean;
private FlowStyle(Boolean flowStyle) {
styleBoolean = flowStyle;
}
/*
* Convenience for legacy constructors that took {@link Boolean} arguments since replaced by {@link FlowStyle}.
* Introduced in v1.22 but only to support that for backwards compatibility.
* @deprecated Since restored in v1.22. Use the {@link FlowStyle} constants in your code instead.
*/
@Deprecated
public static FlowStyle fromBoolean(Boolean flowStyle) {
return flowStyle==null ? AUTO
: flowStyle ? FLOW
: BLOCK;
}
public Boolean getStyleBoolean() {
return styleBoolean;
}
@Override
public String toString() {
return "Flow style: '" + styleBoolean + "'";
}
}
/**
* Platform dependent line break.
*/
public enum LineBreak {
WIN("\r\n"), MAC("\r"), UNIX("\n");
private String lineBreak;
private LineBreak(String lineBreak) {
this.lineBreak = lineBreak;
}
public String getString() {
return lineBreak;
}
@Override
public String toString() {
return "Line break: " + name();
}
public static LineBreak getPlatformLineBreak() {
String platformLineBreak = System.getProperty("line.separator");
for (LineBreak lb : values()) {
if (lb.lineBreak.equals(platformLineBreak)) {
return lb;
}
}
return LineBreak.UNIX;
}
}
/**
* Specification version. Currently supported 1.0 and 1.1
*/
public enum Version {
V1_0(new Integer[] { 1, 0 }), V1_1(new Integer[] { 1, 1 });
private Integer[] version;
private Version(Integer[] version) {
this.version = version;
}
public int major() { return version[0]; }
public int minor() { return version[1]; }
public String getRepresentation() {
return version[0] + "." + version[1];
}
@Override
public String toString() {
return "Version: " + getRepresentation();
}
}
private ScalarStyle defaultStyle = ScalarStyle.PLAIN;
private FlowStyle defaultFlowStyle = FlowStyle.AUTO;
private boolean canonical = false;
private boolean allowUnicode = true;
private boolean allowReadOnlyProperties = false;
private int indent = 2;
private int indicatorIndent = 0;
private int bestWidth = 80;
private boolean splitLines = true;
private LineBreak lineBreak = LineBreak.UNIX;
private boolean explicitStart = false;
private boolean explicitEnd = false;
private TimeZone timeZone = null;
private Version version = null;
private Map<String, String> tags = null;
private Boolean prettyFlow = false;
private AnchorGenerator anchorGenerator = new NumberAnchorGenerator(0);
public boolean isAllowUnicode() {
return allowUnicode;
}
/**
* Specify whether to emit non-ASCII printable Unicode characters.
* The default value is true.
* When set to false then printable non-ASCII characters (Cyrillic, Chinese etc)
* will be not printed but escaped (to support ASCII terminals)
*
* @param allowUnicode
* if allowUnicode is false then all non-ASCII characters are
* escaped
*/
public void setAllowUnicode(boolean allowUnicode) {
this.allowUnicode = allowUnicode;
}
public ScalarStyle getDefaultScalarStyle() {
return defaultStyle;
}
/**
* Set default style for scalars. See YAML 1.1 specification, 2.3 Scalars
* (http://yaml.org/spec/1.1/#id858081)
*
* @param defaultStyle
* set the style for all scalars
*/
public void setDefaultScalarStyle(ScalarStyle defaultStyle) {
if (defaultStyle == null) {
throw new NullPointerException("Use ScalarStyle enum.");
}
this.defaultStyle = defaultStyle;
}
public void setIndent(int indent) {
if (indent < Emitter.MIN_INDENT) {
throw new YAMLException("Indent must be at least " + Emitter.MIN_INDENT);
}
if (indent > Emitter.MAX_INDENT) {
throw new YAMLException("Indent must be at most " + Emitter.MAX_INDENT);
}
this.indent = indent;
}
public int getIndent() {
return this.indent;
}
public void setIndicatorIndent(int indicatorIndent) {
if (indicatorIndent < 0) {
throw new YAMLException("Indicator indent must be non-negative.");
}
if (indicatorIndent > Emitter.MAX_INDENT - 1) {
throw new YAMLException("Indicator indent must be at most Emitter.MAX_INDENT-1: " + (Emitter.MAX_INDENT - 1));
}
this.indicatorIndent = indicatorIndent;
}
public int getIndicatorIndent() {
return this.indicatorIndent;
}
public void setVersion(Version version) {
this.version = version;
}
public Version getVersion() {
return this.version;
}
/**
* Force the emitter to produce a canonical YAML document.
*
* @param canonical
* true produce canonical YAML document
*/
public void setCanonical(boolean canonical) {
this.canonical = canonical;
}
public boolean isCanonical() {
return this.canonical;
}
/**
* Force the emitter to produce a pretty YAML document when using the flow
* style.
*
* @param prettyFlow
* true produce pretty flow YAML document
*/
public void setPrettyFlow(boolean prettyFlow) {
this.prettyFlow = prettyFlow;
}
public boolean isPrettyFlow() {
return this.prettyFlow;
}
/**
* Specify the preferred width to emit scalars. When the scalar
* representation takes more then the preferred with the scalar will be
* split into a few lines. The default is 80.
*
* @param bestWidth
* the preferred width for scalars.
*/
public void setWidth(int bestWidth) {
this.bestWidth = bestWidth;
}
public int getWidth() {
return this.bestWidth;
}
/**
* Specify whether to split lines exceeding preferred width for
* scalars. The default is true.
*
* @param splitLines
* whether to split lines exceeding preferred width for scalars.
*/
public void setSplitLines(boolean splitLines) {
this.splitLines = splitLines;
}
public boolean getSplitLines() {
return this.splitLines;
}
public LineBreak getLineBreak() {
return lineBreak;
}
public void setDefaultFlowStyle(FlowStyle defaultFlowStyle) {
if (defaultFlowStyle == null) {
throw new NullPointerException("Use FlowStyle enum.");
}
this.defaultFlowStyle = defaultFlowStyle;
}
public FlowStyle getDefaultFlowStyle() {
return defaultFlowStyle;
}
/**
* Specify the line break to separate the lines. It is platform specific:
* Windows - "\r\n", old MacOS - "\r", Unix - "\n". The default value is the
* one for Unix.
* @param lineBreak to be used for the input
*/
public void setLineBreak(LineBreak lineBreak) {
if (lineBreak == null) {
throw new NullPointerException("Specify line break.");
}
this.lineBreak = lineBreak;
}
public boolean isExplicitStart() {
return explicitStart;
}
public void setExplicitStart(boolean explicitStart) {
this.explicitStart = explicitStart;
}
public boolean isExplicitEnd() {
return explicitEnd;
}
public void setExplicitEnd(boolean explicitEnd) {
this.explicitEnd = explicitEnd;
}
public Map<String, String> getTags() {
return tags;
}
public void setTags(Map<String, String> tags) {
this.tags = tags;
}
/**
* Report whether read-only JavaBean properties (the ones without setters)
* should be included in the YAML document
*
* @return false when read-only JavaBean properties are not emitted
*/
public boolean isAllowReadOnlyProperties() {
return allowReadOnlyProperties;
}
/**
* Set to true to include read-only JavaBean properties (the ones without
* setters) in the YAML document. By default these properties are not
* included to be able to parse later the same JavaBean.
*
* @param allowReadOnlyProperties
* - true to dump read-only JavaBean properties
*/
public void setAllowReadOnlyProperties(boolean allowReadOnlyProperties) {
this.allowReadOnlyProperties = allowReadOnlyProperties;
}
public TimeZone getTimeZone() {
return timeZone;
}
/**
* Set the timezone to be used for Date. If set to <code>null</code> UTC is
* used.
* @param timeZone for created Dates or null to use UTC
*/
public void setTimeZone(TimeZone timeZone) {
this.timeZone = timeZone;
}
public AnchorGenerator getAnchorGenerator() {
return anchorGenerator;
}
public void setAnchorGenerator(AnchorGenerator anchorGenerator) {
this.anchorGenerator = anchorGenerator;
}
}

View File

@ -0,0 +1,45 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml;
public class LoaderOptions {
private boolean allowDuplicateKeys = true;
public boolean isAllowDuplicateKeys() {
return allowDuplicateKeys;
}
/**
* Allow/Reject duplicate map keys in the YAML file.
*
* Default is to allow.
*
* YAML 1.1 is slightly vague around duplicate entries in the YAML file. The
* best reference is <a href="http://www.yaml.org/spec/1.1/#id862121">
* 3.2.1.3. Nodes Comparison</a> where it hints that a duplicate map key is
* an error.
*
* For future reference, YAML spec 1.2 is clear. The keys MUST be unique.
* <a href="http://www.yaml.org/spec/1.2/spec.html#id2759572">1.3. Relation
* to JSON</a>
* @param allowDuplicateKeys false to reject duplicate mapping keys
*/
public void setAllowDuplicateKeys(boolean allowDuplicateKeys) {
this.allowDuplicateKeys = allowDuplicateKeys;
}
}

View File

@ -0,0 +1,411 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
import io.jenkins.plugins.casc.snakeyaml.introspector.BeanAccess;
import io.jenkins.plugins.casc.snakeyaml.introspector.Property;
import io.jenkins.plugins.casc.snakeyaml.introspector.PropertySubstitute;
import io.jenkins.plugins.casc.snakeyaml.introspector.PropertyUtils;
import io.jenkins.plugins.casc.snakeyaml.nodes.Node;
import io.jenkins.plugins.casc.snakeyaml.nodes.Tag;
/**
* Provides additional runtime information necessary to create a custom Java
* instance.
*
* In general this class is thread-safe and can be used as a singleton, the only
* exception being the PropertyUtils field. A singleton PropertyUtils should be
* constructed and shared between all YAML Constructors used if a singleton
* TypeDescription is used, since Constructor sets its propertyUtils to the
* TypeDescription that is passed to it, hence you may end up in a situation
* when propertyUtils in TypeDescription is from different Constructor.
*/
public class TypeDescription {
final private static Logger log = Logger
.getLogger(TypeDescription.class.getPackage().getName());
private final Class<? extends Object> type;
// class that implements the described type; if set, will be used as a source for constructor.
// If not set - TypeDescription will leave instantiation of an entity to the YAML Constructor
private Class<?> impl;
private Tag tag;
transient private Set<Property> dumpProperties;
transient private PropertyUtils propertyUtils;
transient private boolean delegatesChecked;
private Map<String, PropertySubstitute> properties = Collections.emptyMap();
protected Set<String> excludes = Collections.emptySet();
protected String[] includes = null;
protected BeanAccess beanAccess;
public TypeDescription(Class<? extends Object> clazz, Tag tag) {
this(clazz, tag, null);
}
public TypeDescription(Class<? extends Object> clazz, Tag tag, Class<?> impl) {
this.type = clazz;
this.tag = tag;
this.impl = impl;
beanAccess = null;
}
public TypeDescription(Class<? extends Object> clazz, String tag) {
this(clazz, new Tag(tag), null);
}
public TypeDescription(Class<? extends Object> clazz) {
this(clazz, (Tag) null, null);
}
public TypeDescription(Class<? extends Object> clazz, Class<?> impl) {
this(clazz, null, impl);
}
/**
* Get tag which shall be used to load or dump the type (class).
*
* @return tag to be used. It may be a tag for Language-Independent Types
* (http://www.yaml.org/type/)
*/
public Tag getTag() {
return tag;
}
/**
* Set tag to be used to load or dump the type (class).
*
* @param tag
* local or global tag
*/
public void setTag(Tag tag) {
this.tag = tag;
}
public void setTag(String tag) {
setTag(new Tag(tag));
}
/**
* Get represented type (class)
*
* @return type (class) to be described.
*/
public Class<? extends Object> getType() {
return type;
}
/**
* Specify that the property is a type-safe <code>List</code>.
*
* @param property
* name of the JavaBean property
* @param type
* class of List values
*/
@Deprecated
public void putListPropertyType(String property, Class<? extends Object> type) {
addPropertyParameters(property, type);
}
/**
* Get class of List values for provided JavaBean property.
*
* @param property
* property name
* @return class of List values
*/
@Deprecated
public Class<? extends Object> getListPropertyType(String property) {
if (properties.containsKey(property)) {
Class<?>[] typeArguments = properties.get(property).getActualTypeArguments();
if (typeArguments != null && typeArguments.length > 0) {
return typeArguments[0];
}
}
return null;
}
/**
* Specify that the property is a type-safe <code>Map</code>.
*
* @param property
* property name of this JavaBean
* @param key
* class of keys in Map
* @param value
* class of values in Map
*/
@Deprecated
public void putMapPropertyType(String property, Class<? extends Object> key,
Class<? extends Object> value) {
addPropertyParameters(property, key, value);
}
/**
* Get keys type info for this JavaBean
*
* @param property
* property name of this JavaBean
* @return class of keys in the Map
*/
@Deprecated
public Class<? extends Object> getMapKeyType(String property) {
if (properties.containsKey(property)) {
Class<?>[] typeArguments = properties.get(property).getActualTypeArguments();
if (typeArguments != null && typeArguments.length > 0) {
return typeArguments[0];
}
}
return null;
}
/**
* Get values type info for this JavaBean
*
* @param property
* property name of this JavaBean
* @return class of values in the Map
*/
@Deprecated
public Class<? extends Object> getMapValueType(String property) {
if (properties.containsKey(property)) {
Class<?>[] typeArguments = properties.get(property).getActualTypeArguments();
if (typeArguments != null && typeArguments.length > 1) {
return typeArguments[1];
}
}
return null;
}
/**
* Adds new substitute for property <code>pName</code> parameterized by
* <code>classes</code> to this <code>TypeDescription</code>. If
* <code>pName</code> has been added before - updates parameters with
* <code>classes</code>.
*
* @param pName - parameter name
* @param classes - parameterized by
*/
public void addPropertyParameters(String pName, Class<?>... classes) {
if (!properties.containsKey(pName)) {
substituteProperty(pName, null, null, null, classes);
} else {
PropertySubstitute pr = properties.get(pName);
pr.setActualTypeArguments(classes);
}
}
@Override
public String toString() {
return "TypeDescription for " + getType() + " (tag='" + getTag() + "')";
}
private void checkDelegates() {
Collection<PropertySubstitute> values = properties.values();
for (PropertySubstitute p : values) {
try {
p.setDelegate(discoverProperty(p.getName()));
} catch (YAMLException e) {
}
}
delegatesChecked = true;
}
private Property discoverProperty(String name) {
if (propertyUtils != null) {
if (beanAccess == null) {
return propertyUtils.getProperty(type, name);
}
return propertyUtils.getProperty(type, name, beanAccess);
}
return null;
}
public Property getProperty(String name) {
if (!delegatesChecked) {
checkDelegates();
}
return properties.containsKey(name) ? properties.get(name) : discoverProperty(name);
}
/**
* Adds property substitute for <code>pName</code>
*
* @param pName
* property name
* @param pType
* property type
* @param getter
* method name for getter
* @param setter
* method name for setter
* @param argParams
* actual types for parameterized type (List&lt;?&gt;, Map&lt;?&gt;)
*/
public void substituteProperty(String pName, Class<?> pType, String getter, String setter,
Class<?>... argParams) {
substituteProperty(new PropertySubstitute(pName, pType, getter, setter, argParams));
}
public void substituteProperty(PropertySubstitute substitute) {
if (Collections.EMPTY_MAP == properties) {
properties = new LinkedHashMap<String, PropertySubstitute>();
}
substitute.setTargetType(type);
properties.put(substitute.getName(), substitute);
}
public void setPropertyUtils(PropertyUtils propertyUtils) {
this.propertyUtils = propertyUtils;
}
/* begin: Representer */
public void setIncludes(String... propNames) {
this.includes = (propNames != null && propNames.length > 0) ? propNames : null;
}
public void setExcludes(String... propNames) {
if (propNames != null && propNames.length > 0) {
excludes = new HashSet<String>();
for (String name : propNames) {
excludes.add(name);
}
} else {
excludes = Collections.emptySet();
}
}
public Set<Property> getProperties() {
if (dumpProperties != null) {
return dumpProperties;
}
if (propertyUtils != null) {
if (includes != null) {
dumpProperties = new LinkedHashSet<Property>();
for (String propertyName : includes) {
if (!excludes.contains(propertyName)) {
dumpProperties.add(getProperty(propertyName));
}
}
return dumpProperties;
}
final Set<Property> readableProps = (beanAccess == null)
? propertyUtils.getProperties(type)
: propertyUtils.getProperties(type, beanAccess);
if (properties.isEmpty()) {
if (excludes.isEmpty()) {
return dumpProperties = readableProps;
}
dumpProperties = new LinkedHashSet<Property>();
for (Property property : readableProps) {
if (!excludes.contains(property.getName())) {
dumpProperties.add(property);
}
}
return dumpProperties;
}
if (!delegatesChecked) {
checkDelegates();
}
dumpProperties = new LinkedHashSet<Property>();
for (Property property : properties.values()) {
if (!excludes.contains(property.getName()) && property.isReadable()) {
dumpProperties.add(property);
}
}
for (Property property : readableProps) {
if (!excludes.contains(property.getName())) {
dumpProperties.add(property);
}
}
return dumpProperties;
}
return null;
}
/* end: Representer */
/*------------ Maybe something useful to override :) ---------*/
public boolean setupPropertyType(String key, Node valueNode) {
return false;
}
public boolean setProperty(Object targetBean, String propertyName, Object value)
throws Exception {
return false;
}
/**
* This method should be overridden for TypeDescription implementations that are supposed to implement
* instantiation logic that is different from default one as implemented in YAML constructors.
* Note that even if you override this method, default filling of fields with
* variables from parsed YAML will still occur later.
* @param node - node to construct the instance from
* @return new instance
*/
public Object newInstance(Node node) {
if (impl != null) {
try {
java.lang.reflect.Constructor<?> c = impl.getDeclaredConstructor();
c.setAccessible(true);
return c.newInstance();
} catch (Exception e) {
log.fine(e.getLocalizedMessage());
impl = null;
}
}
return null;
}
public Object newInstance(String propertyName, Node node) {
return null;
}
/**
* Is invoked after entity is filled with values from deserialized YAML
* @param obj - deserialized entity
* @return postprocessed deserialized entity
*/
public Object finalizeConstruction(Object obj) {
return obj;
}
}

View File

@ -0,0 +1,749 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions.FlowStyle;
import io.jenkins.plugins.casc.snakeyaml.composer.Composer;
import io.jenkins.plugins.casc.snakeyaml.constructor.BaseConstructor;
import io.jenkins.plugins.casc.snakeyaml.constructor.Constructor;
import io.jenkins.plugins.casc.snakeyaml.emitter.Emitable;
import io.jenkins.plugins.casc.snakeyaml.emitter.Emitter;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
import io.jenkins.plugins.casc.snakeyaml.events.Event;
import io.jenkins.plugins.casc.snakeyaml.introspector.BeanAccess;
import io.jenkins.plugins.casc.snakeyaml.nodes.Node;
import io.jenkins.plugins.casc.snakeyaml.nodes.Tag;
import io.jenkins.plugins.casc.snakeyaml.parser.Parser;
import io.jenkins.plugins.casc.snakeyaml.parser.ParserImpl;
import io.jenkins.plugins.casc.snakeyaml.reader.StreamReader;
import io.jenkins.plugins.casc.snakeyaml.reader.UnicodeReader;
import io.jenkins.plugins.casc.snakeyaml.representer.Representer;
import io.jenkins.plugins.casc.snakeyaml.resolver.Resolver;
import io.jenkins.plugins.casc.snakeyaml.serializer.Serializer;
/**
* Public YAML interface. Each Thread must have its own instance.
*/
public class Yaml {
protected final Resolver resolver;
private String name;
protected BaseConstructor constructor;
protected Representer representer;
protected DumperOptions dumperOptions;
protected LoaderOptions loadingConfig;
/**
* Create Yaml instance. It is safe to create a few instances and use them
* in different Threads.
*/
public Yaml() {
this(new Constructor(), new Representer(), new DumperOptions(), new LoaderOptions(),
new Resolver());
}
/**
* Create Yaml instance.
*
* @param dumperOptions
* DumperOptions to configure outgoing objects
*/
public Yaml(DumperOptions dumperOptions) {
this(new Constructor(), new Representer(), dumperOptions);
}
/**
* Create Yaml instance.
*
* @param loadingConfig
* LoadingConfig to control load behavior
*/
public Yaml(LoaderOptions loadingConfig) {
this(new Constructor(), new Representer(), new DumperOptions(), loadingConfig);
}
/**
* Create Yaml instance. It is safe to create a few instances and use them
* in different Threads.
*
* @param representer
* Representer to emit outgoing objects
*/
public Yaml(Representer representer) {
this(new Constructor(), representer);
}
/**
* Create Yaml instance. It is safe to create a few instances and use them
* in different Threads.
*
* @param constructor
* BaseConstructor to construct incoming documents
*/
public Yaml(BaseConstructor constructor) {
this(constructor, new Representer());
}
/**
* Create Yaml instance. It is safe to create a few instances and use them
* in different Threads.
*
* @param constructor
* BaseConstructor to construct incoming documents
* @param representer
* Representer to emit outgoing objects
*/
public Yaml(BaseConstructor constructor, Representer representer) {
this(constructor, representer, initDumperOptions(representer));
}
private static DumperOptions initDumperOptions(Representer representer) {
DumperOptions dumperOptions = new DumperOptions();
dumperOptions.setDefaultFlowStyle(representer.getDefaultFlowStyle());
dumperOptions.setDefaultScalarStyle(representer.getDefaultScalarStyle());
dumperOptions.setAllowReadOnlyProperties(representer.getPropertyUtils().isAllowReadOnlyProperties());
dumperOptions.setTimeZone(representer.getTimeZone());
return dumperOptions;
}
/**
* Create Yaml instance. It is safe to create a few instances and use them
* in different Threads.
*
* @param representer
* Representer to emit outgoing objects
* @param dumperOptions
* DumperOptions to configure outgoing objects
*/
public Yaml(Representer representer, DumperOptions dumperOptions) {
this(new Constructor(), representer, dumperOptions, new LoaderOptions(), new Resolver());
}
/**
* Create Yaml instance. It is safe to create a few instances and use them
* in different Threads.
*
* @param constructor
* BaseConstructor to construct incoming documents
* @param representer
* Representer to emit outgoing objects
* @param dumperOptions
* DumperOptions to configure outgoing objects
*/
public Yaml(BaseConstructor constructor, Representer representer, DumperOptions dumperOptions) {
this(constructor, representer, dumperOptions, new LoaderOptions(), new Resolver());
}
/**
* Create Yaml instance. It is safe to create a few instances and use them
* in different Threads.
*
* @param constructor
* BaseConstructor to construct incoming documents
* @param representer
* Representer to emit outgoing objects
* @param dumperOptions
* DumperOptions to configure outgoing objects
* @param loadingConfig
* LoadingConfig to control load behavior
*/
public Yaml(BaseConstructor constructor, Representer representer, DumperOptions dumperOptions,
LoaderOptions loadingConfig) {
this(constructor, representer, dumperOptions, loadingConfig, new Resolver());
}
/**
* Create Yaml instance. It is safe to create a few instances and use them
* in different Threads.
*
* @param constructor
* BaseConstructor to construct incoming documents
* @param representer
* Representer to emit outgoing objects
* @param dumperOptions
* DumperOptions to configure outgoing objects
* @param resolver
* Resolver to detect implicit type
*/
public Yaml(BaseConstructor constructor, Representer representer, DumperOptions dumperOptions,
Resolver resolver) {
this(constructor, representer, dumperOptions, new LoaderOptions(), resolver);
}
/**
* Create Yaml instance. It is safe to create a few instances and use them
* in different Threads.
*
* @param constructor
* BaseConstructor to construct incoming documents
* @param representer
* Representer to emit outgoing objects
* @param dumperOptions
* DumperOptions to configure outgoing objects
* @param loadingConfig
* LoadingConfig to control load behavior
* @param resolver
* Resolver to detect implicit type
*/
public Yaml(BaseConstructor constructor, Representer representer, DumperOptions dumperOptions,
LoaderOptions loadingConfig, Resolver resolver) {
if (!constructor.isExplicitPropertyUtils()) {
constructor.setPropertyUtils(representer.getPropertyUtils());
} else if (!representer.isExplicitPropertyUtils()) {
representer.setPropertyUtils(constructor.getPropertyUtils());
}
this.constructor = constructor;
this.constructor.setAllowDuplicateKeys(loadingConfig.isAllowDuplicateKeys());
if (dumperOptions.getIndent() <= dumperOptions.getIndicatorIndent()) {
throw new YAMLException("Indicator indent must be smaller then indent.");
}
representer.setDefaultFlowStyle(dumperOptions.getDefaultFlowStyle());
representer.setDefaultScalarStyle(dumperOptions.getDefaultScalarStyle());
representer.getPropertyUtils()
.setAllowReadOnlyProperties(dumperOptions.isAllowReadOnlyProperties());
representer.setTimeZone(dumperOptions.getTimeZone());
this.representer = representer;
this.dumperOptions = dumperOptions;
this.loadingConfig = loadingConfig;
this.resolver = resolver;
this.name = "Yaml:" + System.identityHashCode(this);
}
/**
* Serialize a Java object into a YAML String.
*
* @param data
* Java object to be Serialized to YAML
* @return YAML String
*/
public String dump(Object data) {
List<Object> list = new ArrayList<Object>(1);
list.add(data);
return dumpAll(list.iterator());
}
/**
* Produce the corresponding representation tree for a given Object.
*
* @see <a href="http://yaml.org/spec/1.1/#id859333">Figure 3.1. Processing
* Overview</a>
* @param data
* instance to build the representation tree for
* @return representation tree
*/
public Node represent(Object data) {
return representer.represent(data);
}
/**
* Serialize a sequence of Java objects into a YAML String.
*
* @param data
* Iterator with Objects
* @return YAML String with all the objects in proper sequence
*/
public String dumpAll(Iterator<? extends Object> data) {
StringWriter buffer = new StringWriter();
dumpAll(data, buffer, null);
return buffer.toString();
}
/**
* Serialize a Java object into a YAML stream.
*
* @param data
* Java object to be serialized to YAML
* @param output
* stream to write to
*/
public void dump(Object data, Writer output) {
List<Object> list = new ArrayList<Object>(1);
list.add(data);
dumpAll(list.iterator(), output, null);
}
/**
* Serialize a sequence of Java objects into a YAML stream.
*
* @param data
* Iterator with Objects
* @param output
* stream to write to
*/
public void dumpAll(Iterator<? extends Object> data, Writer output) {
dumpAll(data, output, null);
}
private void dumpAll(Iterator<? extends Object> data, Writer output, Tag rootTag) {
Serializer serializer = new Serializer(new Emitter(output, dumperOptions), resolver,
dumperOptions, rootTag);
try {
serializer.open();
while (data.hasNext()) {
Node node = representer.represent(data.next());
serializer.serialize(node);
}
serializer.close();
} catch (IOException e) {
throw new YAMLException(e);
}
}
/**
* <p>
* Serialize a Java object into a YAML string. Override the default root tag
* with <code>rootTag</code>.
* </p>
*
* <p>
* This method is similar to <code>Yaml.dump(data)</code> except that the
* root tag for the whole document is replaced with the given tag. This has
* two main uses.
* </p>
*
* <p>
* First, if the root tag is replaced with a standard YAML tag, such as
* <code>Tag.MAP</code>, then the object will be dumped as a map. The root
* tag will appear as <code>!!map</code>, or blank (implicit !!map).
* </p>
*
* <p>
* Second, if the root tag is replaced by a different custom tag, then the
* document appears to be a different type when loaded. For example, if an
* instance of MyClass is dumped with the tag !!YourClass, then it will be
* handled as an instance of YourClass when loaded.
* </p>
*
* @param data
* Java object to be serialized to YAML
* @param rootTag
* the tag for the whole YAML document. The tag should be Tag.MAP
* for a JavaBean to make the tag disappear (to use implicit tag
* !!map). If <code>null</code> is provided then the standard tag
* with the full class name is used.
* @param flowStyle
* flow style for the whole document. See Chapter 10. Collection
* Styles http://yaml.org/spec/1.1/#id930798. If
* <code>null</code> is provided then the flow style from
* DumperOptions is used.
*
* @return YAML String
*/
public String dumpAs(Object data, Tag rootTag, FlowStyle flowStyle) {
FlowStyle oldStyle = representer.getDefaultFlowStyle();
if (flowStyle != null) {
representer.setDefaultFlowStyle(flowStyle);
}
List<Object> list = new ArrayList<Object>(1);
list.add(data);
StringWriter buffer = new StringWriter();
dumpAll(list.iterator(), buffer, rootTag);
representer.setDefaultFlowStyle(oldStyle);
return buffer.toString();
}
/**
* <p>
* Serialize a Java object into a YAML string. Override the default root tag
* with <code>Tag.MAP</code>.
* </p>
* <p>
* This method is similar to <code>Yaml.dump(data)</code> except that the
* root tag for the whole document is replaced with <code>Tag.MAP</code> tag
* (implicit !!map).
* </p>
* <p>
* Block Mapping is used as the collection style. See 10.2.2. Block Mappings
* (http://yaml.org/spec/1.1/#id934537)
* </p>
*
* @param data
* Java object to be serialized to YAML
* @return YAML String
*/
public String dumpAsMap(Object data) {
return dumpAs(data, Tag.MAP, FlowStyle.BLOCK);
}
/**
* Serialize the representation tree into Events.
*
* @see <a href="http://yaml.org/spec/1.1/#id859333">Processing Overview</a>
* @param data
* representation tree
* @return Event list
*/
public List<Event> serialize(Node data) {
SilentEmitter emitter = new SilentEmitter();
Serializer serializer = new Serializer(emitter, resolver, dumperOptions, null);
try {
serializer.open();
serializer.serialize(data);
serializer.close();
} catch (IOException e) {
throw new YAMLException(e);
}
return emitter.getEvents();
}
private static class SilentEmitter implements Emitable {
private List<Event> events = new ArrayList<Event>(100);
public List<Event> getEvents() {
return events;
}
@Override
public void emit(Event event) throws IOException {
events.add(event);
}
}
/**
* Parse the only YAML document in a String and produce the corresponding
* Java object. (Because the encoding in known BOM is not respected.)
*
* @param yaml
* YAML data to load from (BOM must not be present)
* @param <T>
* the class of the instance to be created
* @return parsed object
*/
@SuppressWarnings("unchecked")
public <T> T load(String yaml) {
return (T) loadFromReader(new StreamReader(yaml), Object.class);
}
/**
* Parse the only YAML document in a stream and produce the corresponding
* Java object.
*
* @param io
* data to load from (BOM is respected to detect encoding and removed from the data)
* @param <T>
* the class of the instance to be created
* @return parsed object
*/
@SuppressWarnings("unchecked")
public <T> T load(InputStream io) {
return (T) loadFromReader(new StreamReader(new UnicodeReader(io)), Object.class);
}
/**
* Parse the only YAML document in a stream and produce the corresponding
* Java object.
*
* @param io
* data to load from (BOM must not be present)
* @param <T>
* the class of the instance to be created
* @return parsed object
*/
@SuppressWarnings("unchecked")
public <T> T load(Reader io) {
return (T) loadFromReader(new StreamReader(io), Object.class);
}
/**
* Parse the only YAML document in a stream and produce the corresponding
* Java object.
*
* @param <T>
* Class is defined by the second argument
* @param io
* data to load from (BOM must not be present)
* @param type
* Class of the object to be created
* @return parsed object
*/
@SuppressWarnings("unchecked")
public <T> T loadAs(Reader io, Class<T> type) {
return (T) loadFromReader(new StreamReader(io), type);
}
/**
* Parse the only YAML document in a String and produce the corresponding
* Java object. (Because the encoding in known BOM is not respected.)
*
* @param <T>
* Class is defined by the second argument
* @param yaml
* YAML data to load from (BOM must not be present)
* @param type
* Class of the object to be created
* @return parsed object
*/
@SuppressWarnings("unchecked")
public <T> T loadAs(String yaml, Class<T> type) {
return (T) loadFromReader(new StreamReader(yaml), type);
}
/**
* Parse the only YAML document in a stream and produce the corresponding
* Java object.
*
* @param <T>
* Class is defined by the second argument
* @param input
* data to load from (BOM is respected to detect encoding and removed from the data)
* @param type
* Class of the object to be created
* @return parsed object
*/
@SuppressWarnings("unchecked")
public <T> T loadAs(InputStream input, Class<T> type) {
return (T) loadFromReader(new StreamReader(new UnicodeReader(input)), type);
}
private Object loadFromReader(StreamReader sreader, Class<?> type) {
Composer composer = new Composer(new ParserImpl(sreader), resolver);
constructor.setComposer(composer);
return constructor.getSingleData(type);
}
/**
* Parse all YAML documents in the Reader and produce corresponding Java
* objects. The documents are parsed only when the iterator is invoked.
*
* @param yaml
* YAML data to load from (BOM must not be present)
* @return an Iterable over the parsed Java objects in this String in proper
* sequence
*/
public Iterable<Object> loadAll(Reader yaml) {
Composer composer = new Composer(new ParserImpl(new StreamReader(yaml)), resolver);
constructor.setComposer(composer);
Iterator<Object> result = new Iterator<Object>() {
@Override
public boolean hasNext() {
return constructor.checkData();
}
@Override
public Object next() {
return constructor.getData();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
return new YamlIterable(result);
}
private static class YamlIterable implements Iterable<Object> {
private Iterator<Object> iterator;
public YamlIterable(Iterator<Object> iterator) {
this.iterator = iterator;
}
@Override
public Iterator<Object> iterator() {
return iterator;
}
}
/**
* Parse all YAML documents in a String and produce corresponding Java
* objects. (Because the encoding in known BOM is not respected.) The
* documents are parsed only when the iterator is invoked.
*
* @param yaml
* YAML data to load from (BOM must not be present)
* @return an Iterable over the parsed Java objects in this String in proper
* sequence
*/
public Iterable<Object> loadAll(String yaml) {
return loadAll(new StringReader(yaml));
}
/**
* Parse all YAML documents in a stream and produce corresponding Java
* objects. The documents are parsed only when the iterator is invoked.
*
* @param yaml
* YAML data to load from (BOM is respected to detect encoding and removed from the data)
* @return an Iterable over the parsed Java objects in this stream in proper
* sequence
*/
public Iterable<Object> loadAll(InputStream yaml) {
return loadAll(new UnicodeReader(yaml));
}
/**
* Parse the first YAML document in a stream and produce the corresponding
* representation tree. (This is the opposite of the represent() method)
*
* @see <a href="http://yaml.org/spec/1.1/#id859333">Figure 3.1. Processing
* Overview</a>
* @param yaml
* YAML document
* @return parsed root Node for the specified YAML document
*/
public Node compose(Reader yaml) {
Composer composer = new Composer(new ParserImpl(new StreamReader(yaml)), resolver);
return composer.getSingleNode();
}
/**
* Parse all YAML documents in a stream and produce corresponding
* representation trees.
*
* @see <a href="http://yaml.org/spec/1.1/#id859333">Processing Overview</a>
* @param yaml
* stream of YAML documents
* @return parsed root Nodes for all the specified YAML documents
*/
public Iterable<Node> composeAll(Reader yaml) {
final Composer composer = new Composer(new ParserImpl(new StreamReader(yaml)), resolver);
Iterator<Node> result = new Iterator<Node>() {
@Override
public boolean hasNext() {
return composer.checkNode();
}
@Override
public Node next() {
return composer.getNode();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
return new NodeIterable(result);
}
private static class NodeIterable implements Iterable<Node> {
private Iterator<Node> iterator;
public NodeIterable(Iterator<Node> iterator) {
this.iterator = iterator;
}
@Override
public Iterator<Node> iterator() {
return iterator;
}
}
/**
* Add an implicit scalar detector. If an implicit scalar value matches the
* given regexp, the corresponding tag is assigned to the scalar.
*
* @param tag
* tag to assign to the node
* @param regexp
* regular expression to match against
* @param first
* a sequence of possible initial characters or null (which means
* any).
*/
public void addImplicitResolver(Tag tag, Pattern regexp, String first) {
resolver.addImplicitResolver(tag, regexp, first);
}
@Override
public String toString() {
return name;
}
/**
* Get a meaningful name. It simplifies debugging in a multi-threaded
* environment. If nothing is set explicitly the address of the instance is
* returned.
*
* @return human readable name
*/
public String getName() {
return name;
}
/**
* Set a meaningful name to be shown in toString()
*
* @param name
* human readable name
*/
public void setName(String name) {
this.name = name;
}
/**
* Parse a YAML stream and produce parsing events.
*
* @see <a href="http://yaml.org/spec/1.1/#id859333">Processing Overview</a>
* @param yaml
* YAML document(s)
* @return parsed events
*/
public Iterable<Event> parse(Reader yaml) {
final Parser parser = new ParserImpl(new StreamReader(yaml));
Iterator<Event> result = new Iterator<Event>() {
@Override
public boolean hasNext() {
return parser.peekEvent() != null;
}
@Override
public Event next() {
return parser.getEvent();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
return new EventIterable(result);
}
private static class EventIterable implements Iterable<Event> {
private Iterator<Event> iterator;
public EventIterable(Iterator<Event> iterator) {
this.iterator = iterator;
}
@Override
public Iterator<Event> iterator() {
return iterator;
}
}
public void setBeanAccess(BeanAccess beanAccess) {
constructor.getPropertyUtils().setBeanAccess(beanAccess);
representer.getPropertyUtils().setBeanAccess(beanAccess);
}
public void addTypeDescription(TypeDescription td) {
constructor.addTypeDescription(td);
representer.addTypeDescription(td);
}
}

View File

@ -0,0 +1,238 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.composer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import io.jenkins.plugins.casc.snakeyaml.events.AliasEvent;
import io.jenkins.plugins.casc.snakeyaml.events.Event;
import io.jenkins.plugins.casc.snakeyaml.events.MappingStartEvent;
import io.jenkins.plugins.casc.snakeyaml.events.NodeEvent;
import io.jenkins.plugins.casc.snakeyaml.events.ScalarEvent;
import io.jenkins.plugins.casc.snakeyaml.events.SequenceStartEvent;
import io.jenkins.plugins.casc.snakeyaml.nodes.MappingNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.Node;
import io.jenkins.plugins.casc.snakeyaml.nodes.NodeId;
import io.jenkins.plugins.casc.snakeyaml.nodes.NodeTuple;
import io.jenkins.plugins.casc.snakeyaml.nodes.ScalarNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.SequenceNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.Tag;
import io.jenkins.plugins.casc.snakeyaml.parser.Parser;
import io.jenkins.plugins.casc.snakeyaml.resolver.Resolver;
/**
* Creates a node graph from parser events.
* <p>
* Corresponds to the 'Compose' step as described in chapter 3.1 of the
* <a href="http://yaml.org/spec/1.1/">YAML Specification</a>.
* </p>
*/
public class Composer {
protected final Parser parser;
private final Resolver resolver;
private final Map<String, Node> anchors;
private final Set<Node> recursiveNodes;
public Composer(Parser parser, Resolver resolver) {
this.parser = parser;
this.resolver = resolver;
this.anchors = new HashMap<String, Node>();
this.recursiveNodes = new HashSet<Node>();
}
/**
* Checks if further documents are available.
*
* @return <code>true</code> if there is at least one more document.
*/
public boolean checkNode() {
// Drop the STREAM-START event.
if (parser.checkEvent(Event.ID.StreamStart)) {
parser.getEvent();
}
// If there are more documents available?
return !parser.checkEvent(Event.ID.StreamEnd);
}
/**
* Reads and composes the next document.
*
* @return The root node of the document or <code>null</code> if no more
* documents are available.
*/
public Node getNode() {
// Drop the DOCUMENT-START event.
parser.getEvent();
// Compose the root node.
Node node = composeNode(null);
// Drop the DOCUMENT-END event.
parser.getEvent();
this.anchors.clear();
recursiveNodes.clear();
return node;
}
/**
* Reads a document from a source that contains only one document.
* <p>
* If the stream contains more than one document an exception is thrown.
* </p>
*
* @return The root node of the document or <code>null</code> if no document
* is available.
*/
public Node getSingleNode() {
// Drop the STREAM-START event.
parser.getEvent();
// Compose a document if the stream is not empty.
Node document = null;
if (!parser.checkEvent(Event.ID.StreamEnd)) {
document = getNode();
}
// Ensure that the stream contains no more documents.
if (!parser.checkEvent(Event.ID.StreamEnd)) {
Event event = parser.getEvent();
throw new ComposerException("expected a single document in the stream",
document.getStartMark(), "but found another document", event.getStartMark());
}
// Drop the STREAM-END event.
parser.getEvent();
return document;
}
private Node composeNode(Node parent) {
if (parent != null) recursiveNodes.add(parent);
final Node node;
if (parser.checkEvent(Event.ID.Alias)) {
AliasEvent event = (AliasEvent) parser.getEvent();
String anchor = event.getAnchor();
if (!anchors.containsKey(anchor)) {
throw new ComposerException(null, null, "found undefined alias " + anchor,
event.getStartMark());
}
node = anchors.get(anchor);
if (recursiveNodes.remove(node)) {
node.setTwoStepsConstruction(true);
}
} else {
NodeEvent event = (NodeEvent) parser.peekEvent();
String anchor = event.getAnchor();
// the check for duplicate anchors has been removed (issue 174)
if (parser.checkEvent(Event.ID.Scalar)) {
node = composeScalarNode(anchor);
} else if (parser.checkEvent(Event.ID.SequenceStart)) {
node = composeSequenceNode(anchor);
} else {
node = composeMappingNode(anchor);
}
}
recursiveNodes.remove(parent);
return node;
}
protected Node composeScalarNode(String anchor) {
ScalarEvent ev = (ScalarEvent) parser.getEvent();
String tag = ev.getTag();
boolean resolved = false;
Tag nodeTag;
if (tag == null || tag.equals("!")) {
nodeTag = resolver.resolve(NodeId.scalar, ev.getValue(),
ev.getImplicit().canOmitTagInPlainScalar());
resolved = true;
} else {
nodeTag = new Tag(tag);
}
Node node = new ScalarNode(nodeTag, resolved, ev.getValue(), ev.getStartMark(),
ev.getEndMark(), ev.getScalarStyle());
if (anchor != null) {
anchors.put(anchor, node);
}
return node;
}
protected Node composeSequenceNode(String anchor) {
SequenceStartEvent startEvent = (SequenceStartEvent) parser.getEvent();
String tag = startEvent.getTag();
Tag nodeTag;
boolean resolved = false;
if (tag == null || tag.equals("!")) {
nodeTag = resolver.resolve(NodeId.sequence, null, startEvent.getImplicit());
resolved = true;
} else {
nodeTag = new Tag(tag);
}
final ArrayList<Node> children = new ArrayList<Node>();
SequenceNode node = new SequenceNode(nodeTag, resolved, children, startEvent.getStartMark(),
null, startEvent.getFlowStyle());
if (anchor != null) {
anchors.put(anchor, node);
}
while (!parser.checkEvent(Event.ID.SequenceEnd)) {
children.add(composeNode(node));
}
Event endEvent = parser.getEvent();
node.setEndMark(endEvent.getEndMark());
return node;
}
protected Node composeMappingNode(String anchor) {
MappingStartEvent startEvent = (MappingStartEvent) parser.getEvent();
String tag = startEvent.getTag();
Tag nodeTag;
boolean resolved = false;
if (tag == null || tag.equals("!")) {
nodeTag = resolver.resolve(NodeId.mapping, null, startEvent.getImplicit());
resolved = true;
} else {
nodeTag = new Tag(tag);
}
final List<NodeTuple> children = new ArrayList<NodeTuple>();
MappingNode node = new MappingNode(nodeTag, resolved, children, startEvent.getStartMark(),
null, startEvent.getFlowStyle());
if (anchor != null) {
anchors.put(anchor, node);
}
while (!parser.checkEvent(Event.ID.MappingEnd)) {
composeMappingChildren(children, node);
}
Event endEvent = parser.getEvent();
node.setEndMark(endEvent.getEndMark());
return node;
}
protected void composeMappingChildren(List<NodeTuple> children, MappingNode node) {
Node itemKey = composeKeyNode(node);
if (itemKey.getTag().equals(Tag.MERGE)) {
node.setMerged(true);
}
Node itemValue = composeValueNode(node);
children.add(new NodeTuple(itemKey, itemValue));
}
protected Node composeKeyNode(MappingNode node) {
return composeNode(node);
}
protected Node composeValueNode(MappingNode node) {
return composeNode(node);
}
}

View File

@ -0,0 +1,27 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.composer;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
import io.jenkins.plugins.casc.snakeyaml.error.MarkedYAMLException;
public class ComposerException extends MarkedYAMLException {
private static final long serialVersionUID = 2146314636913113935L;
protected ComposerException(String context, Mark contextMark, String problem, Mark problemMark) {
super(context, contextMark, problem, problemMark);
}
}

View File

@ -0,0 +1,41 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.constructor;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
import io.jenkins.plugins.casc.snakeyaml.nodes.Node;
/**
* Because recursive structures are not very common we provide a way to save
* some typing when extending a constructor
*/
public abstract class AbstractConstruct implements Construct {
/**
* Fail with a reminder to provide the seconds step for a recursive
* structure
*
* @see io.jenkins.plugins.casc.snakeyaml.constructor.Construct#construct2ndStep(io.jenkins.plugins.casc.snakeyaml.nodes.Node,
* java.lang.Object)
*/
public void construct2ndStep(Node node, Object data) {
if (node.isTwoStepsConstruction()) {
throw new IllegalStateException("Not Implemented in " + getClass().getName());
} else {
throw new YAMLException("Unexpected recursive structure for Node: " + node);
}
}
}

View File

@ -0,0 +1,575 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.constructor;
import java.lang.reflect.Array;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import io.jenkins.plugins.casc.snakeyaml.TypeDescription;
import io.jenkins.plugins.casc.snakeyaml.composer.Composer;
import io.jenkins.plugins.casc.snakeyaml.composer.ComposerException;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
import io.jenkins.plugins.casc.snakeyaml.introspector.PropertyUtils;
import io.jenkins.plugins.casc.snakeyaml.nodes.CollectionNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.MappingNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.Node;
import io.jenkins.plugins.casc.snakeyaml.nodes.NodeId;
import io.jenkins.plugins.casc.snakeyaml.nodes.NodeTuple;
import io.jenkins.plugins.casc.snakeyaml.nodes.ScalarNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.SequenceNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.Tag;
public abstract class BaseConstructor {
/**
* It maps the node kind to the the Construct implementation. When the
* runtime class is known then the implicit tag is ignored.
*/
protected final Map<NodeId, Construct> yamlClassConstructors = new EnumMap<NodeId, Construct>(
NodeId.class);
/**
* It maps the (explicit or implicit) tag to the Construct implementation.
* It is used:
* 1) explicit tag - if present.
* 2) implicit tag - when the runtime class of the instance is unknown (the
* node has the Object.class)
*/
protected final Map<Tag, Construct> yamlConstructors = new HashMap<Tag, Construct>();
/**
* It maps the (explicit or implicit) tag to the Construct implementation.
* It is used when no exact match found.
*/
protected final Map<String, Construct> yamlMultiConstructors = new HashMap<String, Construct>();
protected Composer composer;
final Map<Node, Object> constructedObjects;
private final Set<Node> recursiveObjects;
private final ArrayList<RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>>> maps2fill;
private final ArrayList<RecursiveTuple<Set<Object>, Object>> sets2fill;
protected Tag rootTag;
private PropertyUtils propertyUtils;
private boolean explicitPropertyUtils;
private boolean allowDuplicateKeys = true;
protected final Map<Class<? extends Object>, TypeDescription> typeDefinitions;
protected final Map<Tag, Class<? extends Object>> typeTags;
public BaseConstructor() {
constructedObjects = new HashMap<Node, Object>();
recursiveObjects = new HashSet<Node>();
maps2fill = new ArrayList<RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>>>();
sets2fill = new ArrayList<RecursiveTuple<Set<Object>, Object>>();
typeDefinitions = new HashMap<Class<? extends Object>, TypeDescription>();
typeTags = new HashMap<Tag, Class<? extends Object>>();
rootTag = null;
explicitPropertyUtils = false;
typeDefinitions.put(SortedMap.class, new TypeDescription(SortedMap.class, Tag.OMAP,
TreeMap.class));
typeDefinitions.put(SortedSet.class, new TypeDescription(SortedSet.class, Tag.SET,
TreeSet.class));
}
public void setComposer(Composer composer) {
this.composer = composer;
}
/**
* Check if more documents available
*
* @return true when there are more YAML documents in the stream
*/
public boolean checkData() {
// If there are more documents available?
return composer.checkNode();
}
/**
* Construct and return the next document
*
* @return constructed instance
*/
public Object getData() {
// Construct and return the next document.
composer.checkNode();
Node node = composer.getNode();
if (rootTag != null) {
node.setTag(rootTag);
}
return constructDocument(node);
}
/**
* Ensure that the stream contains a single document and construct it
*
* @param type the class of the instance being created
* @return constructed instance
* @throws ComposerException in case there are more documents in the stream
*/
public Object getSingleData(Class<?> type) {
// Ensure that the stream contains a single document and construct it
Node node = composer.getSingleNode();
if (node != null && !Tag.NULL.equals(node.getTag())) {
if (Object.class != type) {
node.setTag(new Tag(type));
} else if (rootTag != null) {
node.setTag(rootTag);
}
return constructDocument(node);
}
return null;
}
/**
* Construct complete YAML document. Call the second step in case of
* recursive structures. At the end cleans all the state.
*
* @param node root Node
* @return Java instance
*/
protected final Object constructDocument(Node node) {
Object data = constructObject(node);
fillRecursive();
constructedObjects.clear();
recursiveObjects.clear();
return data;
}
private void fillRecursive() {
if (!maps2fill.isEmpty()) {
for (RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>> entry : maps2fill) {
RecursiveTuple<Object, Object> key_value = entry._2();
entry._1().put(key_value._1(), key_value._2());
}
maps2fill.clear();
}
if (!sets2fill.isEmpty()) {
for (RecursiveTuple<Set<Object>, Object> value : sets2fill) {
value._1().add(value._2());
}
sets2fill.clear();
}
}
/**
* Construct object from the specified Node. Return existing instance if the
* node is already constructed.
*
* @param node Node to be constructed
* @return Java instance
*/
protected Object constructObject(Node node) {
if (constructedObjects.containsKey(node)) {
return constructedObjects.get(node);
}
return constructObjectNoCheck(node);
}
protected Object constructObjectNoCheck(Node node) {
if (recursiveObjects.contains(node)) {
throw new ConstructorException(null, null, "found unconstructable recursive node",
node.getStartMark());
}
recursiveObjects.add(node);
Construct constructor = getConstructor(node);
Object data = (constructedObjects.containsKey(node)) ? constructedObjects.get(node)
: constructor.construct(node);
finalizeConstruction(node, data);
constructedObjects.put(node, data);
recursiveObjects.remove(node);
if (node.isTwoStepsConstruction()) {
constructor.construct2ndStep(node, data);
}
return data;
}
/**
* Get the constructor to construct the Node. For implicit tags if the
* runtime class is known a dedicated Construct implementation is used.
* Otherwise the constructor is chosen by the tag.
*
* @param node {@link Node} to construct an instance from
* @return {@link Construct} implementation for the specified node
*/
protected Construct getConstructor(Node node) {
if (node.useClassConstructor()) {
return yamlClassConstructors.get(node.getNodeId());
} else {
Construct constructor = yamlConstructors.get(node.getTag());
if (constructor == null) {
for (String prefix : yamlMultiConstructors.keySet()) {
if (node.getTag().startsWith(prefix)) {
return yamlMultiConstructors.get(prefix);
}
}
return yamlConstructors.get(null);
}
return constructor;
}
}
protected String constructScalar(ScalarNode node) {
return node.getValue();
}
// >>>> DEFAULTS >>>>
protected List<Object> createDefaultList(int initSize) {
return new ArrayList<Object>(initSize);
}
protected Set<Object> createDefaultSet(int initSize) {
return new LinkedHashSet<Object>(initSize);
}
protected Map<Object, Object> createDefaultMap(int initSize) {
// respect order from YAML document
return new LinkedHashMap<Object, Object>(initSize);
}
protected Object createArray(Class<?> type, int size) {
return Array.newInstance(type.getComponentType(), size);
}
// <<<< DEFAULTS <<<<
protected Object finalizeConstruction(Node node, Object data) {
final Class<? extends Object> type = node.getType();
if (typeDefinitions.containsKey(type)) {
return typeDefinitions.get(type).finalizeConstruction(data);
}
return data;
}
// >>>> NEW instance
protected Object newInstance(Node node) {
try {
return newInstance(Object.class, node);
} catch (InstantiationException e) {
throw new YAMLException(e);
}
}
final protected Object newInstance(Class<?> ancestor, Node node) throws InstantiationException {
return newInstance(ancestor, node, true);
}
protected Object newInstance(Class<?> ancestor, Node node, boolean tryDefault)
throws InstantiationException {
final Class<? extends Object> type = node.getType();
if (typeDefinitions.containsKey(type)) {
TypeDescription td = typeDefinitions.get(type);
final Object instance = td.newInstance(node);
if (instance != null) {
return instance;
}
}
if (tryDefault) {
/*
* Removed <code> have InstantiationException in case of abstract
* type
*/
if (ancestor.isAssignableFrom(type) && !Modifier.isAbstract(type.getModifiers())) {
try {
java.lang.reflect.Constructor<?> c = type.getDeclaredConstructor();
c.setAccessible(true);
return c.newInstance();
} catch (NoSuchMethodException e) {
throw new InstantiationException("NoSuchMethodException:"
+ e.getLocalizedMessage());
} catch (Exception e) {
throw new YAMLException(e);
}
}
}
throw new InstantiationException();
}
@SuppressWarnings("unchecked")
protected Set<Object> newSet(CollectionNode<?> node) {
try {
return (Set<Object>) newInstance(Set.class, node);
} catch (InstantiationException e) {
return createDefaultSet(node.getValue().size());
}
}
@SuppressWarnings("unchecked")
protected List<Object> newList(SequenceNode node) {
try {
return (List<Object>) newInstance(List.class, node);
} catch (InstantiationException e) {
return createDefaultList(node.getValue().size());
}
}
@SuppressWarnings("unchecked")
protected Map<Object, Object> newMap(MappingNode node) {
try {
return (Map<Object, Object>) newInstance(Map.class, node);
} catch (InstantiationException e) {
return createDefaultMap(node.getValue().size());
}
}
// <<<< NEW instance
// >>>> Construct => NEW, 2ndStep(filling)
protected List<? extends Object> constructSequence(SequenceNode node) {
List<Object> result = newList(node);
constructSequenceStep2(node, result);
return result;
}
protected Set<? extends Object> constructSet(SequenceNode node) {
Set<Object> result = newSet(node);
constructSequenceStep2(node, result);
return result;
}
protected Object constructArray(SequenceNode node) {
return constructArrayStep2(node, createArray(node.getType(), node.getValue().size()));
}
protected void constructSequenceStep2(SequenceNode node, Collection<Object> collection) {
for (Node child : node.getValue()) {
collection.add(constructObject(child));
}
}
protected Object constructArrayStep2(SequenceNode node, Object array) {
final Class<?> componentType = node.getType().getComponentType();
int index = 0;
for (Node child : node.getValue()) {
// Handle multi-dimensional arrays...
if (child.getType() == Object.class) {
child.setType(componentType);
}
final Object value = constructObject(child);
if (componentType.isPrimitive()) {
// Null values are disallowed for primitives
if (value == null) {
throw new NullPointerException(
"Unable to construct element value for " + child);
}
// Primitive arrays require quite a lot of work.
if (byte.class.equals(componentType)) {
Array.setByte(array, index, ((Number) value).byteValue());
} else if (short.class.equals(componentType)) {
Array.setShort(array, index, ((Number) value).shortValue());
} else if (int.class.equals(componentType)) {
Array.setInt(array, index, ((Number) value).intValue());
} else if (long.class.equals(componentType)) {
Array.setLong(array, index, ((Number) value).longValue());
} else if (float.class.equals(componentType)) {
Array.setFloat(array, index, ((Number) value).floatValue());
} else if (double.class.equals(componentType)) {
Array.setDouble(array, index, ((Number) value).doubleValue());
} else if (char.class.equals(componentType)) {
Array.setChar(array, index, ((Character) value).charValue());
} else if (boolean.class.equals(componentType)) {
Array.setBoolean(array, index, ((Boolean) value).booleanValue());
} else {
throw new YAMLException("unexpected primitive type");
}
} else {
// Non-primitive arrays can simply be assigned:
Array.set(array, index, value);
}
++index;
}
return array;
}
protected Set<Object> constructSet(MappingNode node) {
final Set<Object> set = newSet(node);
constructSet2ndStep(node, set);
return set;
}
protected Map<Object, Object> constructMapping(MappingNode node) {
final Map<Object, Object> mapping = newMap(node);
constructMapping2ndStep(node, mapping);
return mapping;
}
protected void constructMapping2ndStep(MappingNode node, Map<Object, Object> mapping) {
List<NodeTuple> nodeValue = node.getValue();
for (NodeTuple tuple : nodeValue) {
Node keyNode = tuple.getKeyNode();
Node valueNode = tuple.getValueNode();
Object key = constructObject(keyNode);
if (key != null) {
try {
key.hashCode();// check circular dependencies
} catch (Exception e) {
throw new ConstructorException("while constructing a mapping",
node.getStartMark(), "found unacceptable key " + key,
tuple.getKeyNode().getStartMark(), e);
}
}
Object value = constructObject(valueNode);
if (keyNode.isTwoStepsConstruction()) {
/*
* if keyObject is created it 2 steps we should postpone putting
* it in map because it may have different hash after
* initialization compared to clean just created one. And map of
* course does not observe key hashCode changes.
*/
maps2fill.add(0,
new RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>>(
mapping, new RecursiveTuple<Object, Object>(key, value)));
} else {
mapping.put(key, value);
}
}
}
protected void constructSet2ndStep(MappingNode node, Set<Object> set) {
List<NodeTuple> nodeValue = node.getValue();
for (NodeTuple tuple : nodeValue) {
Node keyNode = tuple.getKeyNode();
Object key = constructObject(keyNode);
if (key != null) {
try {
key.hashCode();// check circular dependencies
} catch (Exception e) {
throw new ConstructorException("while constructing a Set", node.getStartMark(),
"found unacceptable key " + key, tuple.getKeyNode().getStartMark(), e);
}
}
if (keyNode.isTwoStepsConstruction()) {
/*
* if keyObject is created it 2 steps we should postpone putting
* it into the set because it may have different hash after
* initialization compared to clean just created one. And set of
* course does not observe value hashCode changes.
*/
sets2fill.add(0, new RecursiveTuple<Set<Object>, Object>(set, key));
} else {
set.add(key);
}
}
}
// <<<< Costruct => NEW, 2ndStep(filling)
// TODO protected List<Object[]> constructPairs(MappingNode node) {
// List<Object[]> pairs = new LinkedList<Object[]>();
// List<Node[]> nodeValue = (List<Node[]>) node.getValue();
// for (Iterator<Node[]> iter = nodeValue.iterator(); iter.hasNext();) {
// Node[] tuple = iter.next();
// Object key = constructObject(Object.class, tuple[0]);
// Object value = constructObject(Object.class, tuple[1]);
// pairs.add(new Object[] { key, value });
// }
// return pairs;
// }
public void setPropertyUtils(PropertyUtils propertyUtils) {
this.propertyUtils = propertyUtils;
explicitPropertyUtils = true;
Collection<TypeDescription> tds = typeDefinitions.values();
for (TypeDescription typeDescription : tds) {
typeDescription.setPropertyUtils(propertyUtils);
}
}
public final PropertyUtils getPropertyUtils() {
if (propertyUtils == null) {
propertyUtils = new PropertyUtils();
}
return propertyUtils;
}
/**
* Make YAML aware how to parse a custom Class. If there is no root Class
* assigned in constructor then the 'root' property of this definition is
* respected.
*
* @param definition to be added to the Constructor
* @return the previous value associated with <tt>definition</tt>, or
* <tt>null</tt> if there was no mapping for <tt>definition</tt>.
*/
public TypeDescription addTypeDescription(TypeDescription definition) {
if (definition == null) {
throw new NullPointerException("TypeDescription is required.");
}
Tag tag = definition.getTag();
typeTags.put(tag, definition.getType());
definition.setPropertyUtils(getPropertyUtils());
return typeDefinitions.put(definition.getType(), definition);
}
private static class RecursiveTuple<T, K> {
private final T _1;
private final K _2;
public RecursiveTuple(T _1, K _2) {
this._1 = _1;
this._2 = _2;
}
public K _2() {
return _2;
}
public T _1() {
return _1;
}
}
public final boolean isExplicitPropertyUtils() {
return explicitPropertyUtils;
}
public boolean isAllowDuplicateKeys() {
return allowDuplicateKeys;
}
public void setAllowDuplicateKeys(boolean allowDuplicateKeys) {
this.allowDuplicateKeys = allowDuplicateKeys;
}
}

View File

@ -0,0 +1,50 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.constructor;
import io.jenkins.plugins.casc.snakeyaml.nodes.Node;
/**
* Provide a way to construct a Java instance out of the composed Node. Support
* recursive objects if it is required. (create Native Data Structure out of
* Node Graph)
*
* @see <a href="http://yaml.org/spec/1.1/#id859109">Chapter 3. Processing YAML
* Information</a>
*/
public interface Construct {
/**
* Construct a Java instance with all the properties injected when it is
* possible.
*
* @param node
* composed Node
* @return a complete Java instance
*/
Object construct(Node node);
/**
* Apply the second step when constructing recursive structures. Because the
* instance is already created it can assign a reference to itself.
*
* @param node
* composed Node
* @param object
* the instance constructed earlier by
* <code>construct(Node node)</code> for the provided Node
*/
void construct2ndStep(Node node, Object object);
}

View File

@ -0,0 +1,658 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.constructor;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import io.jenkins.plugins.casc.snakeyaml.TypeDescription;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
import io.jenkins.plugins.casc.snakeyaml.introspector.Property;
import io.jenkins.plugins.casc.snakeyaml.nodes.MappingNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.Node;
import io.jenkins.plugins.casc.snakeyaml.nodes.NodeId;
import io.jenkins.plugins.casc.snakeyaml.nodes.NodeTuple;
import io.jenkins.plugins.casc.snakeyaml.nodes.ScalarNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.SequenceNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.Tag;
/**
* Construct a custom Java instance.
*/
public class Constructor extends SafeConstructor {
public Constructor() {
this(Object.class);
}
/**
* Create Constructor for the specified class as the root.
*
* @param theRoot
* - the class (usually JavaBean) to be constructed
*/
public Constructor(Class<? extends Object> theRoot) {
this(new TypeDescription(checkRoot(theRoot)));
}
/**
* Ugly Java way to check the argument in the constructor
*/
private static Class<? extends Object> checkRoot(Class<? extends Object> theRoot) {
if (theRoot == null) {
throw new NullPointerException("Root class must be provided.");
} else
return theRoot;
}
public Constructor(TypeDescription theRoot) {
this(theRoot, null);
}
public Constructor(TypeDescription theRoot, Collection<TypeDescription> moreTDs) {
if (theRoot == null) {
throw new NullPointerException("Root type must be provided.");
}
this.yamlConstructors.put(null, new ConstructYamlObject());
if (!Object.class.equals(theRoot.getType())) {
rootTag = new Tag(theRoot.getType());
}
yamlClassConstructors.put(NodeId.scalar, new ConstructScalar());
yamlClassConstructors.put(NodeId.mapping, new ConstructMapping());
yamlClassConstructors.put(NodeId.sequence, new ConstructSequence());
addTypeDescription(theRoot);
if (moreTDs != null) {
for (TypeDescription td : moreTDs) {
addTypeDescription(td);
}
}
}
/**
* Create Constructor for a class which does not have to be in the classpath
* or for a definition from a Spring ApplicationContext.
*
* @param theRoot
* fully qualified class name of the root class (usually
* JavaBean)
* @throws ClassNotFoundException if cannot be loaded by the classloader
*/
public Constructor(String theRoot) throws ClassNotFoundException {
this(Class.forName(check(theRoot)));
}
private static final String check(String s) {
if (s == null) {
throw new NullPointerException("Root type must be provided.");
}
if (s.trim().length() == 0) {
throw new YAMLException("Root type must be provided.");
}
return s;
}
/**
* Construct mapping instance (Map, JavaBean) when the runtime class is
* known.
*/
protected class ConstructMapping implements Construct {
/**
* Construct JavaBean. If type safe collections are used please look at
* <code>TypeDescription</code>.
*
* @param node
* node where the keys are property names (they can only be
* <code>String</code>s) and values are objects to be created
* @return constructed JavaBean
*/
public Object construct(Node node) {
MappingNode mnode = (MappingNode) node;
if (Map.class.isAssignableFrom(node.getType())) {
if (node.isTwoStepsConstruction()) {
return newMap(mnode);
} else {
return constructMapping(mnode);
}
} else if (Collection.class.isAssignableFrom(node.getType())) {
if (node.isTwoStepsConstruction()) {
return newSet(mnode);
} else {
return constructSet(mnode);
}
} else {
Object obj = Constructor.this.newInstance(mnode);
if (node.isTwoStepsConstruction()) {
return obj;
} else {
return constructJavaBean2ndStep(mnode, obj);
}
}
}
@SuppressWarnings("unchecked")
public void construct2ndStep(Node node, Object object) {
if (Map.class.isAssignableFrom(node.getType())) {
constructMapping2ndStep((MappingNode) node, (Map<Object, Object>) object);
} else if (Set.class.isAssignableFrom(node.getType())) {
constructSet2ndStep((MappingNode) node, (Set<Object>) object);
} else {
constructJavaBean2ndStep((MappingNode) node, object);
}
}
// protected Object createEmptyJavaBean(MappingNode node) {
// try {
// Object instance = Constructor.this.newInstance(node);
// if (instance != null) {
// return instance;
// }
//
// /**
// * Using only default constructor. Everything else will be
// * initialized on 2nd step. If we do here some partial
// * initialization, how do we then track what need to be done on
// * 2nd step? I think it is better to get only object here (to
// * have it as reference for recursion) and do all other thing on
// * 2nd step.
// */
// java.lang.reflect.Constructor<?> c =
// node.getType().getDeclaredConstructor();
// c.setAccessible(true);
// return c.newInstance();
// } catch (Exception e) {
// throw new YAMLException(e);
// }
// }
protected Object constructJavaBean2ndStep(MappingNode node, Object object) {
flattenMapping(node);
Class<? extends Object> beanType = node.getType();
List<NodeTuple> nodeValue = node.getValue();
for (NodeTuple tuple : nodeValue) {
ScalarNode keyNode;
if (tuple.getKeyNode() instanceof ScalarNode) {
// key must be scalar
keyNode = (ScalarNode) tuple.getKeyNode();
} else {
throw new YAMLException(
"Keys must be scalars but found: " + tuple.getKeyNode());
}
Node valueNode = tuple.getValueNode();
// keys can only be Strings
keyNode.setType(String.class);
String key = (String) constructObject(keyNode);
try {
TypeDescription memberDescription = typeDefinitions.get(beanType);
Property property = memberDescription == null ? getProperty(beanType, key)
: memberDescription.getProperty(key);
if (!property.isWritable()) {
throw new YAMLException("No writable property '" + key + "' on class: "
+ beanType.getName());
}
valueNode.setType(property.getType());
final boolean typeDetected = (memberDescription != null)
? memberDescription.setupPropertyType(key, valueNode)
: false;
if (!typeDetected && valueNode.getNodeId() != NodeId.scalar) {
// only if there is no explicit TypeDescription
Class<?>[] arguments = property.getActualTypeArguments();
if (arguments != null && arguments.length > 0) {
// type safe (generic) collection may contain the
// proper class
if (valueNode.getNodeId() == NodeId.sequence) {
Class<?> t = arguments[0];
SequenceNode snode = (SequenceNode) valueNode;
snode.setListType(t);
} else if (Set.class.isAssignableFrom(valueNode.getType())) {
Class<?> t = arguments[0];
MappingNode mnode = (MappingNode) valueNode;
mnode.setOnlyKeyType(t);
mnode.setUseClassConstructor(true);
} else if (Map.class.isAssignableFrom(valueNode.getType())) {
Class<?> ketType = arguments[0];
Class<?> valueType = arguments[1];
MappingNode mnode = (MappingNode) valueNode;
mnode.setTypes(ketType, valueType);
mnode.setUseClassConstructor(true);
}
}
}
Object value = (memberDescription != null)
? newInstance(memberDescription, key, valueNode)
: constructObject(valueNode);
// Correct when the property expects float but double was
// constructed
if (property.getType() == Float.TYPE || property.getType() == Float.class) {
if (value instanceof Double) {
value = ((Double) value).floatValue();
}
}
// Correct when the property a String but the value is binary
if (property.getType() == String.class && Tag.BINARY.equals(valueNode.getTag())
&& value instanceof byte[]) {
value = new String((byte[]) value);
}
if (memberDescription == null
|| !memberDescription.setProperty(object, key, value)) {
property.set(object, value);
}
} catch (DuplicateKeyException e) {
throw e;
} catch (Exception e) {
throw new ConstructorException(
"Cannot create property=" + key + " for JavaBean=" + object,
node.getStartMark(), e.getMessage(), valueNode.getStartMark(), e);
}
}
return object;
}
private Object newInstance(TypeDescription memberDescription, String propertyName,
Node node) {
Object newInstance = memberDescription.newInstance(propertyName, node);
if (newInstance != null) {
constructedObjects.put(node, newInstance);
return constructObjectNoCheck(node);
}
return constructObject(node);
}
protected Property getProperty(Class<? extends Object> type, String name) {
return getPropertyUtils().getProperty(type, name);
}
}
/**
* Construct an instance when the runtime class is not known but a global
* tag with a class name is defined. It delegates the construction to the
* appropriate constructor based on the node kind (scalar, sequence,
* mapping)
*/
protected class ConstructYamlObject implements Construct {
private Construct getConstructor(Node node) {
Class<?> cl = getClassForNode(node);
node.setType(cl);
// call the constructor as if the runtime class is defined
Construct constructor = yamlClassConstructors.get(node.getNodeId());
return constructor;
}
public Object construct(Node node) {
try {
return getConstructor(node).construct(node);
} catch (ConstructorException e) {
throw e;
} catch (Exception e) {
throw new ConstructorException(null, null, "Can't construct a java object for "
+ node.getTag() + "; exception=" + e.getMessage(), node.getStartMark(), e);
}
}
public void construct2ndStep(Node node, Object object) {
try {
getConstructor(node).construct2ndStep(node, object);
} catch (Exception e) {
throw new ConstructorException(
null, null, "Can't construct a second step for a java object for "
+ node.getTag() + "; exception=" + e.getMessage(),
node.getStartMark(), e);
}
}
}
/**
* Construct scalar instance when the runtime class is known. Recursive
* structures are not supported.
*/
protected class ConstructScalar extends AbstractConstruct {
public Object construct(Node nnode) {
ScalarNode node = (ScalarNode) nnode;
Class<?> type = node.getType();
try {
return newInstance(type, node, false);
} catch (InstantiationException e1) {
}
Object result;
if (type.isPrimitive() || type == String.class || Number.class.isAssignableFrom(type)
|| type == Boolean.class || Date.class.isAssignableFrom(type)
|| type == Character.class || type == BigInteger.class
|| type == BigDecimal.class || Enum.class.isAssignableFrom(type)
|| Tag.BINARY.equals(node.getTag()) || Calendar.class.isAssignableFrom(type)
|| type == UUID.class) {
// standard classes created directly
result = constructStandardJavaInstance(type, node);
} else {
// there must be only 1 constructor with 1 argument
java.lang.reflect.Constructor<?>[] javaConstructors = type
.getDeclaredConstructors();
int oneArgCount = 0;
java.lang.reflect.Constructor<?> javaConstructor = null;
for (java.lang.reflect.Constructor<?> c : javaConstructors) {
if (c.getParameterTypes().length == 1) {
oneArgCount++;
javaConstructor = c;
}
}
Object argument;
if (javaConstructor == null) {
try {
return newInstance(type, node, false);
} catch (InstantiationException ie) {
throw new YAMLException("No single argument constructor found for " + type
+ " : " + ie.getMessage());
}
} else if (oneArgCount == 1) {
argument = constructStandardJavaInstance(javaConstructor.getParameterTypes()[0],
node);
} else {
// TODO it should be possible to use implicit types instead
// of forcing String. Resolver must be available here to
// obtain the implicit tag. Then we can set the tag and call
// callConstructor(node) to create the argument instance.
// On the other hand it may be safer to require a custom
// constructor to avoid guessing the argument class
argument = constructScalar(node);
try {
javaConstructor = type.getDeclaredConstructor(String.class);
} catch (Exception e) {
throw new YAMLException("Can't construct a java object for scalar "
+ node.getTag() + "; No String constructor found. Exception="
+ e.getMessage(), e);
}
}
try {
javaConstructor.setAccessible(true);
result = javaConstructor.newInstance(argument);
} catch (Exception e) {
throw new ConstructorException(null, null,
"Can't construct a java object for scalar " + node.getTag()
+ "; exception=" + e.getMessage(),
node.getStartMark(), e);
}
}
return result;
}
@SuppressWarnings("unchecked")
private Object constructStandardJavaInstance(@SuppressWarnings("rawtypes") Class type,
ScalarNode node) {
Object result;
if (type == String.class) {
Construct stringConstructor = yamlConstructors.get(Tag.STR);
result = stringConstructor.construct(node);
} else if (type == Boolean.class || type == Boolean.TYPE) {
Construct boolConstructor = yamlConstructors.get(Tag.BOOL);
result = boolConstructor.construct(node);
} else if (type == Character.class || type == Character.TYPE) {
Construct charConstructor = yamlConstructors.get(Tag.STR);
String ch = (String) charConstructor.construct(node);
if (ch.length() == 0) {
result = null;
} else if (ch.length() != 1) {
throw new YAMLException(
"Invalid node Character: '" + ch + "'; length: " + ch.length());
} else {
result = Character.valueOf(ch.charAt(0));
}
} else if (Date.class.isAssignableFrom(type)) {
Construct dateConstructor = yamlConstructors.get(Tag.TIMESTAMP);
Date date = (Date) dateConstructor.construct(node);
if (type == Date.class) {
result = date;
} else {
try {
java.lang.reflect.Constructor<?> constr = type.getConstructor(long.class);
result = constr.newInstance(date.getTime());
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new YAMLException("Cannot construct: '" + type + "'");
}
}
} else if (type == Float.class || type == Double.class || type == Float.TYPE
|| type == Double.TYPE || type == BigDecimal.class) {
if (type == BigDecimal.class) {
result = new BigDecimal(node.getValue());
} else {
Construct doubleConstructor = yamlConstructors.get(Tag.FLOAT);
result = doubleConstructor.construct(node);
if (type == Float.class || type == Float.TYPE) {
result = Float.valueOf(((Double) result).floatValue());
}
}
} else if (type == Byte.class || type == Short.class || type == Integer.class
|| type == Long.class || type == BigInteger.class || type == Byte.TYPE
|| type == Short.TYPE || type == Integer.TYPE || type == Long.TYPE) {
Construct intConstructor = yamlConstructors.get(Tag.INT);
result = intConstructor.construct(node);
if (type == Byte.class || type == Byte.TYPE) {
result = Byte.valueOf(result.toString());
} else if (type == Short.class || type == Short.TYPE) {
result = Short.valueOf(result.toString());
} else if (type == Integer.class || type == Integer.TYPE) {
result = Integer.parseInt(result.toString());
} else if (type == Long.class || type == Long.TYPE) {
result = Long.valueOf(result.toString());
} else {
// only BigInteger left
result = new BigInteger(result.toString());
}
} else if (Enum.class.isAssignableFrom(type)) {
String enumValueName = node.getValue();
try {
result = Enum.valueOf(type, enumValueName);
} catch (Exception ex) {
throw new YAMLException("Unable to find enum value '" + enumValueName
+ "' for enum class: " + type.getName());
}
} else if (Calendar.class.isAssignableFrom(type)) {
ConstructYamlTimestamp contr = new ConstructYamlTimestamp();
contr.construct(node);
result = contr.getCalendar();
} else if (Number.class.isAssignableFrom(type)) {
//since we do not know the exact type we create Float
ConstructYamlFloat contr = new ConstructYamlFloat();
result = contr.construct(node);
} else if (UUID.class == type) {
result = UUID.fromString(node.getValue());
} else {
if (yamlConstructors.containsKey(node.getTag())) {
result = yamlConstructors.get(node.getTag()).construct(node);
} else {
throw new YAMLException("Unsupported class: " + type);
}
}
return result;
}
}
/**
* Construct sequence (List, Array, or immutable object) when the runtime
* class is known.
*/
protected class ConstructSequence implements Construct {
@SuppressWarnings("unchecked")
public Object construct(Node node) {
SequenceNode snode = (SequenceNode) node;
if (Set.class.isAssignableFrom(node.getType())) {
if (node.isTwoStepsConstruction()) {
throw new YAMLException("Set cannot be recursive.");
} else {
return constructSet(snode);
}
} else if (Collection.class.isAssignableFrom(node.getType())) {
if (node.isTwoStepsConstruction()) {
return newList(snode);
} else {
return constructSequence(snode);
}
} else if (node.getType().isArray()) {
if (node.isTwoStepsConstruction()) {
return createArray(node.getType(), snode.getValue().size());
} else {
return constructArray(snode);
}
} else {
// create immutable object
List<java.lang.reflect.Constructor<?>> possibleConstructors = new ArrayList<java.lang.reflect.Constructor<?>>(
snode.getValue().size());
for (java.lang.reflect.Constructor<?> constructor : node.getType()
.getDeclaredConstructors()) {
if (snode.getValue().size() == constructor.getParameterTypes().length) {
possibleConstructors.add(constructor);
}
}
if (!possibleConstructors.isEmpty()) {
if (possibleConstructors.size() == 1) {
Object[] argumentList = new Object[snode.getValue().size()];
java.lang.reflect.Constructor<?> c = possibleConstructors.get(0);
int index = 0;
for (Node argumentNode : snode.getValue()) {
Class<?> type = c.getParameterTypes()[index];
// set runtime classes for arguments
argumentNode.setType(type);
argumentList[index++] = constructObject(argumentNode);
}
try {
c.setAccessible(true);
return c.newInstance(argumentList);
} catch (Exception e) {
throw new YAMLException(e);
}
}
// use BaseConstructor
List<Object> argumentList = (List<Object>) constructSequence(snode);
Class<?>[] parameterTypes = new Class[argumentList.size()];
int index = 0;
for (Object parameter : argumentList) {
parameterTypes[index] = parameter.getClass();
index++;
}
for (java.lang.reflect.Constructor<?> c : possibleConstructors) {
Class<?>[] argTypes = c.getParameterTypes();
boolean foundConstructor = true;
for (int i = 0; i < argTypes.length; i++) {
if (!wrapIfPrimitive(argTypes[i]).isAssignableFrom(parameterTypes[i])) {
foundConstructor = false;
break;
}
}
if (foundConstructor) {
try {
c.setAccessible(true);
return c.newInstance(argumentList.toArray());
} catch (Exception e) {
throw new YAMLException(e);
}
}
}
}
throw new YAMLException(
"No suitable constructor with " + String.valueOf(snode.getValue().size())
+ " arguments found for " + node.getType());
}
}
private final Class<? extends Object> wrapIfPrimitive(Class<?> clazz) {
if (!clazz.isPrimitive()) {
return clazz;
}
if (clazz == Integer.TYPE) {
return Integer.class;
}
if (clazz == Float.TYPE) {
return Float.class;
}
if (clazz == Double.TYPE) {
return Double.class;
}
if (clazz == Boolean.TYPE) {
return Boolean.class;
}
if (clazz == Long.TYPE) {
return Long.class;
}
if (clazz == Character.TYPE) {
return Character.class;
}
if (clazz == Short.TYPE) {
return Short.class;
}
if (clazz == Byte.TYPE) {
return Byte.class;
}
throw new YAMLException("Unexpected primitive " + clazz);
}
@SuppressWarnings("unchecked")
public void construct2ndStep(Node node, Object object) {
SequenceNode snode = (SequenceNode) node;
if (List.class.isAssignableFrom(node.getType())) {
List<Object> list = (List<Object>) object;
constructSequenceStep2(snode, list);
} else if (node.getType().isArray()) {
constructArrayStep2(snode, object);
} else {
throw new YAMLException("Immutable objects cannot be recursive.");
}
}
}
protected Class<?> getClassForNode(Node node) {
Class<? extends Object> classForTag = typeTags.get(node.getTag());
if (classForTag == null) {
String name = node.getTag().getClassName();
Class<?> cl;
try {
cl = getClassForName(name);
} catch (ClassNotFoundException e) {
throw new YAMLException("Class not found: " + name);
}
typeTags.put(node.getTag(), cl);
return cl;
} else {
return classForTag;
}
}
protected Class<?> getClassForName(String name) throws ClassNotFoundException {
try {
return Class.forName(name, true, Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException e) {
return Class.forName(name);
}
}
}

View File

@ -0,0 +1,33 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.constructor;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
import io.jenkins.plugins.casc.snakeyaml.error.MarkedYAMLException;
public class ConstructorException extends MarkedYAMLException {
private static final long serialVersionUID = -8816339931365239910L;
protected ConstructorException(String context, Mark contextMark, String problem,
Mark problemMark, Throwable cause) {
super(context, contextMark, problem, problemMark, cause);
}
protected ConstructorException(String context, Mark contextMark, String problem,
Mark problemMark) {
this(context, contextMark, problem, problemMark, null);
}
}

View File

@ -0,0 +1,40 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.constructor;
/**
* Construct instances with a custom Class Loader.
*/
public class CustomClassLoaderConstructor extends Constructor {
private ClassLoader loader = CustomClassLoaderConstructor.class.getClassLoader();
public CustomClassLoaderConstructor(ClassLoader cLoader) {
this(Object.class, cLoader);
}
public CustomClassLoaderConstructor(Class<? extends Object> theRoot, ClassLoader theLoader) {
super(theRoot);
if (theLoader == null) {
throw new NullPointerException("Loader must be provided.");
}
this.loader = theLoader;
}
@Override
protected Class<?> getClassForName(String name) throws ClassNotFoundException {
return Class.forName(name, true, loader);
}
}

View File

@ -0,0 +1,26 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.constructor;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
public class DuplicateKeyException extends ConstructorException {
protected DuplicateKeyException(Mark contextMark, Object key,
Mark problemMark) {
super("while constructing a mapping", contextMark, "found duplicate key " + key.toString(), problemMark);
}
}

View File

@ -0,0 +1,544 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.constructor;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
import io.jenkins.plugins.casc.snakeyaml.external.biz.base64Coder.Base64Coder;
import io.jenkins.plugins.casc.snakeyaml.nodes.MappingNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.Node;
import io.jenkins.plugins.casc.snakeyaml.nodes.NodeId;
import io.jenkins.plugins.casc.snakeyaml.nodes.NodeTuple;
import io.jenkins.plugins.casc.snakeyaml.nodes.ScalarNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.SequenceNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.Tag;
/**
* Construct standard Java classes
*/
public class SafeConstructor extends BaseConstructor {
public static final ConstructUndefined undefinedConstructor = new ConstructUndefined();
public SafeConstructor() {
this.yamlConstructors.put(Tag.NULL, new ConstructYamlNull());
this.yamlConstructors.put(Tag.BOOL, new ConstructYamlBool());
this.yamlConstructors.put(Tag.INT, new ConstructYamlInt());
this.yamlConstructors.put(Tag.FLOAT, new ConstructYamlFloat());
this.yamlConstructors.put(Tag.BINARY, new ConstructYamlBinary());
this.yamlConstructors.put(Tag.TIMESTAMP, new ConstructYamlTimestamp());
this.yamlConstructors.put(Tag.OMAP, new ConstructYamlOmap());
this.yamlConstructors.put(Tag.PAIRS, new ConstructYamlPairs());
this.yamlConstructors.put(Tag.SET, new ConstructYamlSet());
this.yamlConstructors.put(Tag.STR, new ConstructYamlStr());
this.yamlConstructors.put(Tag.SEQ, new ConstructYamlSeq());
this.yamlConstructors.put(Tag.MAP, new ConstructYamlMap());
this.yamlConstructors.put(null, undefinedConstructor);
this.yamlClassConstructors.put(NodeId.scalar, undefinedConstructor);
this.yamlClassConstructors.put(NodeId.sequence, undefinedConstructor);
this.yamlClassConstructors.put(NodeId.mapping, undefinedConstructor);
}
protected void flattenMapping(MappingNode node) {
// perform merging only on nodes containing merge node(s)
processDuplicateKeys(node);
if (node.isMerged()) {
node.setValue(mergeNode(node, true, new HashMap<Object, Integer>(),
new ArrayList<NodeTuple>()));
}
}
protected void processDuplicateKeys(MappingNode node) {
List<NodeTuple> nodeValue = node.getValue();
Map<Object, Integer> keys = new HashMap<Object, Integer>(nodeValue.size());
TreeSet<Integer> toRemove = new TreeSet<Integer>();
int i = 0;
for (NodeTuple tuple : nodeValue) {
Node keyNode = tuple.getKeyNode();
if (!keyNode.getTag().equals(Tag.MERGE)) {
Object key = constructObject(keyNode);
if (key != null) {
try {
key.hashCode();// check circular dependencies
} catch (Exception e) {
throw new ConstructorException("while constructing a mapping",
node.getStartMark(), "found unacceptable key " + key,
tuple.getKeyNode().getStartMark(), e);
}
}
Integer prevIndex = keys.put(key, i);
if (prevIndex != null) {
if (!isAllowDuplicateKeys()) {
throw new DuplicateKeyException(node.getStartMark(), key,
tuple.getKeyNode().getStartMark());
}
toRemove.add(prevIndex);
}
}
i = i + 1;
}
Iterator<Integer> indicies2remove = toRemove.descendingIterator();
while (indicies2remove.hasNext()) {
nodeValue.remove(indicies2remove.next().intValue());
}
}
/**
* Does merge for supplied mapping node.
*
* @param node
* where to merge
* @param isPreffered
* true if keys of node should take precedence over others...
* @param key2index
* maps already merged keys to index from values
* @param values
* collects merged NodeTuple
* @return list of the merged NodeTuple (to be set as value for the
* MappingNode)
*/
private List<NodeTuple> mergeNode(MappingNode node, boolean isPreffered,
Map<Object, Integer> key2index, List<NodeTuple> values) {
Iterator<NodeTuple> iter = node.getValue().iterator();
while (iter.hasNext()) {
final NodeTuple nodeTuple = iter.next();
final Node keyNode = nodeTuple.getKeyNode();
final Node valueNode = nodeTuple.getValueNode();
if (keyNode.getTag().equals(Tag.MERGE)) {
iter.remove();
switch (valueNode.getNodeId()) {
case mapping:
MappingNode mn = (MappingNode) valueNode;
mergeNode(mn, false, key2index, values);
break;
case sequence:
SequenceNode sn = (SequenceNode) valueNode;
List<Node> vals = sn.getValue();
for (Node subnode : vals) {
if (!(subnode instanceof MappingNode)) {
throw new ConstructorException("while constructing a mapping",
node.getStartMark(),
"expected a mapping for merging, but found "
+ subnode.getNodeId(),
subnode.getStartMark());
}
MappingNode mnode = (MappingNode) subnode;
mergeNode(mnode, false, key2index, values);
}
break;
default:
throw new ConstructorException("while constructing a mapping",
node.getStartMark(),
"expected a mapping or list of mappings for merging, but found "
+ valueNode.getNodeId(),
valueNode.getStartMark());
}
} else {
// we need to construct keys to avoid duplications
Object key = constructObject(keyNode);
if (!key2index.containsKey(key)) { // 1st time merging key
values.add(nodeTuple);
// keep track where tuple for the key is
key2index.put(key, values.size() - 1);
} else if (isPreffered) { // there is value for the key, but we
// need to override it
// change value for the key using saved position
values.set(key2index.get(key), nodeTuple);
}
}
}
return values;
}
@Override
protected void constructMapping2ndStep(MappingNode node, Map<Object, Object> mapping) {
flattenMapping(node);
super.constructMapping2ndStep(node, mapping);
}
@Override
protected void constructSet2ndStep(MappingNode node, Set<Object> set) {
flattenMapping(node);
super.constructSet2ndStep(node, set);
}
public class ConstructYamlNull extends AbstractConstruct {
@Override
public Object construct(Node node) {
constructScalar((ScalarNode) node);
return null;
}
}
private final static Map<String, Boolean> BOOL_VALUES = new HashMap<String, Boolean>();
static {
BOOL_VALUES.put("yes", Boolean.TRUE);
BOOL_VALUES.put("no", Boolean.FALSE);
BOOL_VALUES.put("true", Boolean.TRUE);
BOOL_VALUES.put("false", Boolean.FALSE);
BOOL_VALUES.put("on", Boolean.TRUE);
BOOL_VALUES.put("off", Boolean.FALSE);
}
public class ConstructYamlBool extends AbstractConstruct {
@Override
public Object construct(Node node) {
String val = (String) constructScalar((ScalarNode) node);
return BOOL_VALUES.get(val.toLowerCase());
}
}
public class ConstructYamlInt extends AbstractConstruct {
@Override
public Object construct(Node node) {
String value = constructScalar((ScalarNode) node).toString().replaceAll("_", "");
int sign = +1;
char first = value.charAt(0);
if (first == '-') {
sign = -1;
value = value.substring(1);
} else if (first == '+') {
value = value.substring(1);
}
int base = 10;
if ("0".equals(value)) {
return Integer.valueOf(0);
} else if (value.startsWith("0b")) {
value = value.substring(2);
base = 2;
} else if (value.startsWith("0x")) {
value = value.substring(2);
base = 16;
} else if (value.startsWith("0")) {
value = value.substring(1);
base = 8;
} else if (value.indexOf(':') != -1) {
String[] digits = value.split(":");
int bes = 1;
int val = 0;
for (int i = 0, j = digits.length; i < j; i++) {
val += Long.parseLong(digits[j - i - 1]) * bes;
bes *= 60;
}
return createNumber(sign, String.valueOf(val), 10);
} else {
return createNumber(sign, value, 10);
}
return createNumber(sign, value, base);
}
}
private Number createNumber(int sign, String number, int radix) {
Number result;
if (sign < 0) {
number = "-" + number;
}
try {
result = Integer.valueOf(number, radix);
} catch (NumberFormatException e) {
try {
result = Long.valueOf(number, radix);
} catch (NumberFormatException e1) {
result = new BigInteger(number, radix);
}
}
return result;
}
public class ConstructYamlFloat extends AbstractConstruct {
@Override
public Object construct(Node node) {
String value = constructScalar((ScalarNode) node).toString().replaceAll("_", "");
int sign = +1;
char first = value.charAt(0);
if (first == '-') {
sign = -1;
value = value.substring(1);
} else if (first == '+') {
value = value.substring(1);
}
String valLower = value.toLowerCase();
if (".inf".equals(valLower)) {
return Double
.valueOf(sign == -1 ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);
} else if (".nan".equals(valLower)) {
return Double.valueOf(Double.NaN);
} else if (value.indexOf(':') != -1) {
String[] digits = value.split(":");
int bes = 1;
double val = 0.0;
for (int i = 0, j = digits.length; i < j; i++) {
val += Double.parseDouble(digits[j - i - 1]) * bes;
bes *= 60;
}
return Double.valueOf(sign * val);
} else {
Double d = Double.valueOf(value);
return Double.valueOf(d.doubleValue() * sign);
}
}
}
public class ConstructYamlBinary extends AbstractConstruct {
@Override
public Object construct(Node node) {
// Ignore white spaces for base64 encoded scalar
String noWhiteSpaces = constructScalar((ScalarNode) node).toString().replaceAll("\\s",
"");
byte[] decoded = Base64Coder.decode(noWhiteSpaces.toCharArray());
return decoded;
}
}
private final static Pattern TIMESTAMP_REGEXP = Pattern.compile(
"^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:(?:[Tt]|[ \t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \t]*(?:Z|([-+][0-9][0-9]?)(?::([0-9][0-9])?)?))?)?$");
private final static Pattern YMD_REGEXP = Pattern
.compile("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)$");
public static class ConstructYamlTimestamp extends AbstractConstruct {
private Calendar calendar;
public Calendar getCalendar() {
return calendar;
}
@Override
public Object construct(Node node) {
ScalarNode scalar = (ScalarNode) node;
String nodeValue = scalar.getValue();
Matcher match = YMD_REGEXP.matcher(nodeValue);
if (match.matches()) {
String year_s = match.group(1);
String month_s = match.group(2);
String day_s = match.group(3);
calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
calendar.clear();
calendar.set(Calendar.YEAR, Integer.parseInt(year_s));
// Java's months are zero-based...
calendar.set(Calendar.MONTH, Integer.parseInt(month_s) - 1); // x
calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day_s));
return calendar.getTime();
} else {
match = TIMESTAMP_REGEXP.matcher(nodeValue);
if (!match.matches()) {
throw new YAMLException("Unexpected timestamp: " + nodeValue);
}
String year_s = match.group(1);
String month_s = match.group(2);
String day_s = match.group(3);
String hour_s = match.group(4);
String min_s = match.group(5);
// seconds and milliseconds
String seconds = match.group(6);
String millis = match.group(7);
if (millis != null) {
seconds = seconds + "." + millis;
}
double fractions = Double.parseDouble(seconds);
int sec_s = (int) Math.round(Math.floor(fractions));
int usec = (int) Math.round((fractions - sec_s) * 1000);
// timezone
String timezoneh_s = match.group(8);
String timezonem_s = match.group(9);
TimeZone timeZone;
if (timezoneh_s != null) {
String time = timezonem_s != null ? ":" + timezonem_s : "00";
timeZone = TimeZone.getTimeZone("GMT" + timezoneh_s + time);
} else {
// no time zone provided
timeZone = TimeZone.getTimeZone("UTC");
}
calendar = Calendar.getInstance(timeZone);
calendar.set(Calendar.YEAR, Integer.parseInt(year_s));
// Java's months are zero-based...
calendar.set(Calendar.MONTH, Integer.parseInt(month_s) - 1);
calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day_s));
calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hour_s));
calendar.set(Calendar.MINUTE, Integer.parseInt(min_s));
calendar.set(Calendar.SECOND, sec_s);
calendar.set(Calendar.MILLISECOND, usec);
return calendar.getTime();
}
}
}
public class ConstructYamlOmap extends AbstractConstruct {
@Override
public Object construct(Node node) {
// Note: we do not check for duplicate keys, because it's too
// CPU-expensive.
Map<Object, Object> omap = new LinkedHashMap<Object, Object>();
if (!(node instanceof SequenceNode)) {
throw new ConstructorException("while constructing an ordered map",
node.getStartMark(), "expected a sequence, but found " + node.getNodeId(),
node.getStartMark());
}
SequenceNode snode = (SequenceNode) node;
for (Node subnode : snode.getValue()) {
if (!(subnode instanceof MappingNode)) {
throw new ConstructorException("while constructing an ordered map",
node.getStartMark(),
"expected a mapping of length 1, but found " + subnode.getNodeId(),
subnode.getStartMark());
}
MappingNode mnode = (MappingNode) subnode;
if (mnode.getValue().size() != 1) {
throw new ConstructorException("while constructing an ordered map",
node.getStartMark(), "expected a single mapping item, but found "
+ mnode.getValue().size() + " items",
mnode.getStartMark());
}
Node keyNode = mnode.getValue().get(0).getKeyNode();
Node valueNode = mnode.getValue().get(0).getValueNode();
Object key = constructObject(keyNode);
Object value = constructObject(valueNode);
omap.put(key, value);
}
return omap;
}
}
public class ConstructYamlPairs extends AbstractConstruct {
@Override
public Object construct(Node node) {
// Note: we do not check for duplicate keys, because it's too
// CPU-expensive.
if (!(node instanceof SequenceNode)) {
throw new ConstructorException("while constructing pairs", node.getStartMark(),
"expected a sequence, but found " + node.getNodeId(), node.getStartMark());
}
SequenceNode snode = (SequenceNode) node;
List<Object[]> pairs = new ArrayList<Object[]>(snode.getValue().size());
for (Node subnode : snode.getValue()) {
if (!(subnode instanceof MappingNode)) {
throw new ConstructorException("while constructingpairs", node.getStartMark(),
"expected a mapping of length 1, but found " + subnode.getNodeId(),
subnode.getStartMark());
}
MappingNode mnode = (MappingNode) subnode;
if (mnode.getValue().size() != 1) {
throw new ConstructorException("while constructing pairs", node.getStartMark(),
"expected a single mapping item, but found " + mnode.getValue().size()
+ " items",
mnode.getStartMark());
}
Node keyNode = mnode.getValue().get(0).getKeyNode();
Node valueNode = mnode.getValue().get(0).getValueNode();
Object key = constructObject(keyNode);
Object value = constructObject(valueNode);
pairs.add(new Object[] { key, value });
}
return pairs;
}
}
public class ConstructYamlSet implements Construct {
@Override
public Object construct(Node node) {
if (node.isTwoStepsConstruction()) {
return (constructedObjects.containsKey(node) ? constructedObjects.get(node)
: createDefaultSet(((MappingNode) node).getValue().size()));
} else {
return constructSet((MappingNode) node);
}
}
@Override
@SuppressWarnings("unchecked")
public void construct2ndStep(Node node, Object object) {
if (node.isTwoStepsConstruction()) {
constructSet2ndStep((MappingNode) node, (Set<Object>) object);
} else {
throw new YAMLException("Unexpected recursive set structure. Node: " + node);
}
}
}
public class ConstructYamlStr extends AbstractConstruct {
@Override
public Object construct(Node node) {
return constructScalar((ScalarNode) node);
}
}
public class ConstructYamlSeq implements Construct {
@Override
public Object construct(Node node) {
SequenceNode seqNode = (SequenceNode) node;
if (node.isTwoStepsConstruction()) {
return newList(seqNode);
} else {
return constructSequence(seqNode);
}
}
@Override
@SuppressWarnings("unchecked")
public void construct2ndStep(Node node, Object data) {
if (node.isTwoStepsConstruction()) {
constructSequenceStep2((SequenceNode) node, (List<Object>) data);
} else {
throw new YAMLException("Unexpected recursive sequence structure. Node: " + node);
}
}
}
public class ConstructYamlMap implements Construct {
@Override
public Object construct(Node node) {
MappingNode mnode = (MappingNode) node;
if (node.isTwoStepsConstruction()) {
return createDefaultMap(mnode.getValue().size());
} else {
return constructMapping(mnode);
}
}
@Override
@SuppressWarnings("unchecked")
public void construct2ndStep(Node node, Object object) {
if (node.isTwoStepsConstruction()) {
constructMapping2ndStep((MappingNode) node, (Map<Object, Object>) object);
} else {
throw new YAMLException("Unexpected recursive mapping structure. Node: " + node);
}
}
}
public static final class ConstructUndefined extends AbstractConstruct {
@Override
public Object construct(Node node) {
throw new ConstructorException(null, null,
"could not determine a constructor for the tag " + node.getTag(),
node.getStartMark());
}
}
}

View File

@ -0,0 +1,24 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.emitter;
import java.io.IOException;
import io.jenkins.plugins.casc.snakeyaml.events.Event;
public interface Emitable {
void emit(Event event) throws IOException;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,26 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.emitter;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
public class EmitterException extends YAMLException {
private static final long serialVersionUID = -8280070025452995908L;
public EmitterException(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,25 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.emitter;
import java.io.IOException;
/**
* Python's methods are first class object. Java needs a class.
*/
interface EmitterState {
void expect() throws IOException;
}

View File

@ -0,0 +1,37 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.emitter;
public final class ScalarAnalysis {
public String scalar;
public boolean empty;
public boolean multiline;
public boolean allowFlowPlain;
public boolean allowBlockPlain;
public boolean allowSingleQuoted;
public boolean allowBlock;
public ScalarAnalysis(String scalar, boolean empty, boolean multiline, boolean allowFlowPlain,
boolean allowBlockPlain, boolean allowSingleQuoted, boolean allowBlock) {
this.scalar = scalar;
this.empty = empty;
this.multiline = multiline;
this.allowFlowPlain = allowFlowPlain;
this.allowBlockPlain = allowBlockPlain;
this.allowSingleQuoted = allowSingleQuoted;
this.allowBlock = allowBlock;
}
}

View File

@ -0,0 +1,165 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.error;
import java.io.Serializable;
import io.jenkins.plugins.casc.snakeyaml.scanner.Constant;
/**
* It's just a record and its only use is producing nice error messages. Parser
* does not use it for any other purposes.
*/
public final class Mark implements Serializable {
private String name;
private int index;
private int line;
private int column;
private int[] buffer;
private int pointer;
private static int[] toCodePoints(char[] str) {
int[] codePoints = new int[Character.codePointCount(str, 0, str.length)];
for (int i = 0, c = 0; i < str.length; c++) {
int cp = Character.codePointAt(str, i);
codePoints[c] = cp;
i += Character.charCount(cp);
}
return codePoints;
}
public Mark(String name, int index, int line, int column, char[] str, int pointer) {
this(name, index, line, column, toCodePoints(str), pointer);
}
/*
* Existed in older versions but replaced with {@code char[]}-based constructor.
* Restored in v1.22 for backwards compatibility.
* @deprecated Since restored in v1.22. Use {@link Mark#Mark(String, int, int, int, char[], int)}.
*/
@Deprecated
public Mark(String name, int index, int line, int column, String buffer, int pointer) {
this(name, index, line, column, buffer.toCharArray(), pointer);
}
public Mark(String name, int index, int line, int column, int[] buffer, int pointer) {
super();
this.name = name;
this.index = index;
this.line = line;
this.column = column;
this.buffer = buffer;
this.pointer = pointer;
}
private boolean isLineBreak(int c) {
return Constant.NULL_OR_LINEBR.has(c);
}
public String get_snippet(int indent, int max_length) {
float half = max_length / 2 - 1;
int start = pointer;
String head = "";
while ((start > 0) && !isLineBreak(buffer[start - 1])) {
start -= 1;
if (pointer - start > half) {
head = " ... ";
start += 5;
break;
}
}
String tail = "";
int end = pointer;
while ((end < buffer.length) && !isLineBreak(buffer[end])) {
end += 1;
if (end - pointer > half) {
tail = " ... ";
end -= 5;
break;
}
}
StringBuilder result = new StringBuilder();
for (int i = 0; i < indent; i++) {
result.append(" ");
}
result.append(head);
for (int i = start; i < end; i++) {
result.appendCodePoint(buffer[i]);
}
result.append(tail);
result.append("\n");
for (int i = 0; i < indent + pointer - start + head.length(); i++) {
result.append(" ");
}
result.append("^");
return result.toString();
}
public String get_snippet() {
return get_snippet(4, 75);
}
@Override
public String toString() {
String snippet = get_snippet();
StringBuilder builder = new StringBuilder(" in ");
builder.append(name);
builder.append(", line ");
builder.append(line + 1);
builder.append(", column ");
builder.append(column + 1);
builder.append(":\n");
builder.append(snippet);
return builder.toString();
}
public String getName() {
return name;
}
/**
* starts with 0
* @return line number
*/
public int getLine() {
return line;
}
/**
* starts with 0
* @return column number
*/
public int getColumn() {
return column;
}
/**
* starts with 0
* @return character number
*/
public int getIndex() {
return index;
}
public int[] getBuffer() {
return buffer;
}
public int getPointer() {
return pointer;
}
}

View File

@ -0,0 +1,101 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.error;
public class MarkedYAMLException extends YAMLException {
private static final long serialVersionUID = -9119388488683035101L;
private String context;
private Mark contextMark;
private String problem;
private Mark problemMark;
private String note;
protected MarkedYAMLException(String context, Mark contextMark, String problem,
Mark problemMark, String note) {
this(context, contextMark, problem, problemMark, note, null);
}
protected MarkedYAMLException(String context, Mark contextMark, String problem,
Mark problemMark, String note, Throwable cause) {
super(context + "; " + problem + "; " + problemMark, cause);
this.context = context;
this.contextMark = contextMark;
this.problem = problem;
this.problemMark = problemMark;
this.note = note;
}
protected MarkedYAMLException(String context, Mark contextMark, String problem, Mark problemMark) {
this(context, contextMark, problem, problemMark, null, null);
}
protected MarkedYAMLException(String context, Mark contextMark, String problem,
Mark problemMark, Throwable cause) {
this(context, contextMark, problem, problemMark, null, cause);
}
@Override
public String getMessage() {
return toString();
}
@Override
public String toString() {
StringBuilder lines = new StringBuilder();
if (context != null) {
lines.append(context);
lines.append("\n");
}
if (contextMark != null
&& (problem == null || problemMark == null
|| contextMark.getName().equals(problemMark.getName())
|| (contextMark.getLine() != problemMark.getLine()) || (contextMark
.getColumn() != problemMark.getColumn()))) {
lines.append(contextMark.toString());
lines.append("\n");
}
if (problem != null) {
lines.append(problem);
lines.append("\n");
}
if (problemMark != null) {
lines.append(problemMark.toString());
lines.append("\n");
}
if (note != null) {
lines.append(note);
lines.append("\n");
}
return lines.toString();
}
public String getContext() {
return context;
}
public Mark getContextMark() {
return contextMark;
}
public String getProblem() {
return problem;
}
public Mark getProblemMark() {
return problemMark;
}
}

View File

@ -0,0 +1,32 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.error;
public class YAMLException extends RuntimeException {
private static final long serialVersionUID = -4738336175050337570L;
public YAMLException(String message) {
super(message);
}
public YAMLException(Throwable cause) {
super(cause);
}
public YAMLException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,33 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.events;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Marks the inclusion of a previously anchored node.
*/
public final class AliasEvent extends NodeEvent {
public AliasEvent(String anchor, Mark startMark, Mark endMark) {
super(anchor, startMark, endMark);
if(anchor == null) throw new NullPointerException();
}
@Override
public boolean is(Event.ID id) {
return ID.Alias == id;
}
}

View File

@ -0,0 +1,28 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.events;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Base class for the end events of the collection nodes.
*/
public abstract class CollectionEndEvent extends Event {
public CollectionEndEvent(Mark startMark, Mark endMark) {
super(startMark, endMark);
}
}

View File

@ -0,0 +1,90 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.events;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Base class for the start events of the collection nodes.
*/
public abstract class CollectionStartEvent extends NodeEvent {
private final String tag;
// The implicit flag of a collection start event indicates if the tag may be
// omitted when the collection is emitted
private final boolean implicit;
// flag indicates if a collection is block or flow
private final DumperOptions.FlowStyle flowStyle;
public CollectionStartEvent(String anchor, String tag, boolean implicit, Mark startMark,
Mark endMark, DumperOptions.FlowStyle flowStyle) {
super(anchor, startMark, endMark);
this.tag = tag;
this.implicit = implicit;
if(flowStyle == null) throw new NullPointerException("Flow style must be provided.");
this.flowStyle = flowStyle;
}
/*
* Existed in older versions but replaced with {@link DumperOptions.FlowStyle}-based constructor.
* Restored in v1.22 for backwards compatibility.
* @deprecated Since restored in v1.22. Use {@link CollectionStartEvent#CollectionStartEvent(String, String, boolean, Mark, Mark, io.jenkins.plugins.casc.snakeyaml.DumperOptions.FlowStyle) }.
*/
@Deprecated
public CollectionStartEvent(String anchor, String tag, boolean implicit, Mark startMark,
Mark endMark, Boolean flowStyle) {
this(anchor, tag, implicit, startMark, endMark, DumperOptions.FlowStyle.fromBoolean(flowStyle));
}
/**
* Tag of this collection.
*
* @return The tag of this collection, or <code>null</code> if no explicit
* tag is available.
*/
public String getTag() {
return this.tag;
}
/**
* <code>true</code> if the tag can be omitted while this collection is
* emitted.
*
* @return True if the tag can be omitted while this collection is emitted.
*/
public boolean getImplicit() {
return this.implicit;
}
/**
* <code>true</code> if this collection is in flow style, <code>false</code>
* for block style.
*
* @return If this collection is in flow style.
*/
public DumperOptions.FlowStyle getFlowStyle() {
return this.flowStyle;
}
@Override
protected String getArguments() {
return super.getArguments() + ", tag=" + tag + ", implicit=" + implicit;
}
public boolean isFlow() {
return DumperOptions.FlowStyle.FLOW == flowStyle;
}
}

View File

@ -0,0 +1,42 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.events;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Marks the end of a document.
* <p>
* This event follows the document's content.
* </p>
*/
public final class DocumentEndEvent extends Event {
private final boolean explicit;
public DocumentEndEvent(Mark startMark, Mark endMark, boolean explicit) {
super(startMark, endMark);
this.explicit = explicit;
}
public boolean getExplicit() {
return explicit;
}
@Override
public boolean is(Event.ID id) {
return ID.DocumentEnd == id;
}
}

View File

@ -0,0 +1,72 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.events;
import java.util.Map;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions.Version;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Marks the beginning of a document.
* <p>
* This event followed by the document's content and a {@link DocumentEndEvent}.
* </p>
*/
public final class DocumentStartEvent extends Event {
private final boolean explicit;
private final Version version;
private final Map<String, String> tags;
public DocumentStartEvent(Mark startMark, Mark endMark, boolean explicit, Version version,
Map<String, String> tags) {
super(startMark, endMark);
this.explicit = explicit;
this.version = version;
this.tags = tags;
}
public boolean getExplicit() {
return explicit;
}
/**
* YAML version the document conforms to.
*
* @return <code>null</code>if the document has no explicit
* <code>%YAML</code> directive. Otherwise an array with two
* components, the major and minor part of the version (in this
* order).
*/
public Version getVersion() {
return version;
}
/**
* Tag shorthands as defined by the <code>%TAG</code> directive.
*
* @return Mapping of 'handles' to 'prefixes' (the handles include the '!'
* characters).
*/
public Map<String, String> getTags() {
return tags;
}
@Override
public boolean is(Event.ID id) {
return ID.DocumentStart == id;
}
}

View File

@ -0,0 +1,79 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.events;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Basic unit of output from a {@link io.jenkins.plugins.casc.snakeyaml.parser.Parser} or input
* of a {@link io.jenkins.plugins.casc.snakeyaml.emitter.Emitter}.
*/
public abstract class Event {
public enum ID {
Alias, DocumentEnd, DocumentStart, MappingEnd, MappingStart, Scalar, SequenceEnd, SequenceStart, StreamEnd, StreamStart
}
private final Mark startMark;
private final Mark endMark;
public Event(Mark startMark, Mark endMark) {
this.startMark = startMark;
this.endMark = endMark;
}
public String toString() {
return "<" + this.getClass().getName() + "(" + getArguments() + ")>";
}
public Mark getStartMark() {
return startMark;
}
public Mark getEndMark() {
return endMark;
}
/**
* Generate human readable representation of the Event
* @see "__repr__ for Event in PyYAML"
* @return representation fore humans
*/
protected String getArguments() {
return "";
}
public abstract boolean is(Event.ID id);
/*
* for tests only
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof Event) {
return toString().equals(obj.toString());
} else {
return false;
}
}
/*
* for tests only
*/
@Override
public int hashCode() {
return toString().hashCode();
}
}

View File

@ -0,0 +1,58 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.events;
/**
* The implicit flag of a scalar event is a pair of boolean values that indicate
* if the tag may be omitted when the scalar is emitted in a plain and non-plain
* style correspondingly.
*
* @see <a href="http://pyyaml.org/wiki/PyYAMLDocumentation#Events">Events</a>
*/
public class ImplicitTuple {
private final boolean plain;
private final boolean nonPlain;
public ImplicitTuple(boolean plain, boolean nonplain) {
this.plain = plain;
this.nonPlain = nonplain;
}
/**
* @return true when tag may be omitted when the scalar is emitted in a
* plain style.
*/
public boolean canOmitTagInPlainScalar() {
return plain;
}
/**
* @return true when tag may be omitted when the scalar is emitted in a
* non-plain style.
*/
public boolean canOmitTagInNonPlainScalar() {
return nonPlain;
}
public boolean bothFalse() {
return !plain && !nonPlain;
}
@Override
public String toString() {
return "implicit=[" + plain + ", " + nonPlain + "]";
}
}

View File

@ -0,0 +1,35 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.events;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Marks the end of a mapping node.
*
* @see MappingStartEvent
*/
public final class MappingEndEvent extends CollectionEndEvent {
public MappingEndEvent(Mark startMark, Mark endMark) {
super(startMark, endMark);
}
@Override
public boolean is(Event.ID id) {
return ID.MappingEnd == id;
}
}

View File

@ -0,0 +1,56 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.events;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Marks the beginning of a mapping node.
* <p>
* This event is followed by a number of key value pairs. <br>
* The pairs are not in any particular order. However, the value always directly
* follows the corresponding key. <br>
* After the key value pairs follows a {@link MappingEndEvent}.
* </p>
* <p>
* There must be an even number of node events between the start and end event.
* </p>
*
* @see MappingEndEvent
*/
public final class MappingStartEvent extends CollectionStartEvent {
public MappingStartEvent(String anchor, String tag, boolean implicit, Mark startMark,
Mark endMark, DumperOptions.FlowStyle flowStyle) {
super(anchor, tag, implicit, startMark, endMark, flowStyle);
}
/*
* Existed in older versions but replaced with {@link DumperOptions.FlowStyle}-based constructor.
* Restored in v1.22 for backwards compatibility.
* @deprecated Since restored in v1.22. Use {@link MappingStartEvent#CollectionStartEvent(String, String, boolean, Mark, Mark, io.jenkins.plugins.casc.snakeyaml.DumperOptions.FlowStyle) }.
*/
@Deprecated
public MappingStartEvent(String anchor, String tag, boolean implicit, Mark startMark,
Mark endMark, Boolean flowStyle) {
this(anchor, tag, implicit, startMark, endMark, DumperOptions.FlowStyle.fromBoolean(flowStyle));
}
@Override
public boolean is(Event.ID id) {
return ID.MappingStart == id;
}
}

View File

@ -0,0 +1,49 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.events;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Base class for all events that mark the beginning of a node.
*/
public abstract class NodeEvent extends Event {
private final String anchor;
public NodeEvent(String anchor, Mark startMark, Mark endMark) {
super(startMark, endMark);
this.anchor = anchor;
}
/**
* Node anchor by which this node might later be referenced by a
* {@link AliasEvent}.
* <p>
* Note that {@link AliasEvent}s are by it self <code>NodeEvent</code>s and
* use this property to indicate the referenced anchor.
*
* @return Anchor of this node or <code>null</code> if no anchor is defined.
*/
public String getAnchor() {
return this.anchor;
}
@Override
protected String getArguments() {
return "anchor=" + anchor;
}
}

View File

@ -0,0 +1,128 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.events;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Marks a scalar value.
*/
public final class ScalarEvent extends NodeEvent {
private final String tag;
// style flag of a scalar event indicates the style of the scalar. Possible
// values are None, '', '\'', '"', '|', '>'
private final DumperOptions.ScalarStyle style;
private final String value;
// The implicit flag of a scalar event is a pair of boolean values that
// indicate if the tag may be omitted when the scalar is emitted in a plain
// and non-plain style correspondingly.
private final ImplicitTuple implicit;
public ScalarEvent(String anchor, String tag, ImplicitTuple implicit, String value,
Mark startMark, Mark endMark, DumperOptions.ScalarStyle style) {
super(anchor, startMark, endMark);
this.tag = tag;
this.implicit = implicit;
if (value == null) throw new NullPointerException("Value must be provided.");
this.value = value;
if (style == null) throw new NullPointerException("Style must be provided.");
this.style = style;
}
/*
* Existed in older versions but replaced with {@link DumperOptions.ScalarStyle}-based constructor.
* Restored in v1.22 for backwards compatibility.
* @deprecated Since restored in v1.22. Use {@link ScalarEvent#ScalarEvent(String, String, ImplicitTuple, String, Mark, Mark, io.jenkins.plugins.casc.snakeyaml.DumperOptions.ScalarStyle) }.
*/
@Deprecated
public ScalarEvent(String anchor, String tag, ImplicitTuple implicit, String value,
Mark startMark, Mark endMark, Character style) {
this(anchor, tag, implicit, value, startMark, endMark, DumperOptions.ScalarStyle.createStyle(style));
}
/**
* Tag of this scalar.
*
* @return The tag of this scalar, or <code>null</code> if no explicit tag
* is available.
*/
public String getTag() {
return this.tag;
}
/**
* Style of the scalar.
* <dl>
* <dt>null</dt>
* <dd>Flow Style - Plain</dd>
* <dt>'\''</dt>
* <dd>Flow Style - Single-Quoted</dd>
* <dt>'"'</dt>
* <dd>Flow Style - Double-Quoted</dd>
* <dt>'|'</dt>
* <dd>Block Style - Literal</dd>
* <dt>'&gt;'</dt>
* <dd>Block Style - Folded</dd>
* </dl>
*
* @see <a href="http://yaml.org/spec/1.1/#id864487">Kind/Style
* Combinations</a>
* @return Style of the scalar.
*/
public DumperOptions.ScalarStyle getScalarStyle() {
return this.style;
}
/**
* @deprecated use getScalarStyle() instead
* @return char which is a value behind ScalarStyle
*/
@Deprecated
public Character getStyle() {
return this.style.getChar();
}
/**
* String representation of the value.
* <p>
* Without quotes and escaping.
* </p>
*
* @return Value as Unicode string.
*/
public String getValue() {
return this.value;
}
public ImplicitTuple getImplicit() {
return this.implicit;
}
@Override
protected String getArguments() {
return super.getArguments() + ", tag=" + tag + ", " + implicit + ", value=" + value;
}
@Override
public boolean is(Event.ID id) {
return ID.Scalar == id;
}
public boolean isPlain() {
return style == DumperOptions.ScalarStyle.PLAIN;
}
}

View File

@ -0,0 +1,35 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.events;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Marks the end of a sequence.
*
* @see SequenceStartEvent
*/
public final class SequenceEndEvent extends CollectionEndEvent {
public SequenceEndEvent(Mark startMark, Mark endMark) {
super(startMark, endMark);
}
@Override
public boolean is(Event.ID id) {
return ID.SequenceEnd == id;
}
}

View File

@ -0,0 +1,51 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.events;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Marks the beginning of a sequence node.
* <p>
* This event is followed by the elements contained in the sequence, and a
* {@link SequenceEndEvent}.
* </p>
*
* @see SequenceEndEvent
*/
public final class SequenceStartEvent extends CollectionStartEvent {
public SequenceStartEvent(String anchor, String tag, boolean implicit, Mark startMark,
Mark endMark, DumperOptions.FlowStyle flowStyle) {
super(anchor, tag, implicit, startMark, endMark, flowStyle);
}
/*
* Existed in older versions but replaced with {@link DumperOptions.SequenceStyle}-based constructor.
* Restored in v1.22 for backwards compatibility.
* @deprecated Since restored in v1.22. Use {@link SequenceStartEvent#SequenceStartEvent(String, String, boolean, Mark, Mark, io.jenkins.plugins.casc.snakeyaml.DumperOptions.FlowStyle) }.
*/
@Deprecated
public SequenceStartEvent(String anchor, String tag, boolean implicit, Mark startMark,
Mark endMark, Boolean flowStyle) {
this(anchor, tag, implicit, startMark, endMark, DumperOptions.FlowStyle.fromBoolean(flowStyle));
}
@Override
public boolean is(Event.ID id) {
return ID.SequenceStart == id;
}
}

View File

@ -0,0 +1,40 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.events;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Marks the end of a stream that might have contained multiple documents.
* <p>
* This event is the last event that a parser emits. Together with
* {@link StreamStartEvent} (which is the first event a parser emits) they mark
* the beginning and the end of a stream of documents.
* </p>
* <p>
* See {@link Event} for an exemplary output.
* </p>
*/
public final class StreamEndEvent extends Event {
public StreamEndEvent(Mark startMark, Mark endMark) {
super(startMark, endMark);
}
@Override
public boolean is(Event.ID id) {
return ID.StreamEnd == id;
}
}

View File

@ -0,0 +1,41 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.events;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Marks the start of a stream that might contain multiple documents.
* <p>
* This event is the first event that a parser emits. Together with
* {@link StreamEndEvent} (which is the last event a parser emits) they mark the
* beginning and the end of a stream of documents.
* </p>
* <p>
* See {@link Event} for an exemplary output.
* </p>
*/
public final class StreamStartEvent extends Event {
public StreamStartEvent(Mark startMark, Mark endMark) {
super(startMark, endMark);
}
@Override
public boolean is(Event.ID id) {
return ID.StreamStart == id;
}
}

View File

@ -0,0 +1,235 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.extensions.compactnotation;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import io.jenkins.plugins.casc.snakeyaml.constructor.Construct;
import io.jenkins.plugins.casc.snakeyaml.constructor.Constructor;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
import io.jenkins.plugins.casc.snakeyaml.introspector.Property;
import io.jenkins.plugins.casc.snakeyaml.nodes.MappingNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.Node;
import io.jenkins.plugins.casc.snakeyaml.nodes.NodeTuple;
import io.jenkins.plugins.casc.snakeyaml.nodes.ScalarNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.SequenceNode;
/**
* Construct a custom Java instance out of a compact object notation format.
*/
public class CompactConstructor extends Constructor {
private static final Pattern GUESS_COMPACT = Pattern
.compile("\\p{Alpha}.*\\s*\\((?:,?\\s*(?:(?:\\w*)|(?:\\p{Alpha}\\w*\\s*=.+))\\s*)+\\)");
private static final Pattern FIRST_PATTERN = Pattern.compile("(\\p{Alpha}.*)(\\s*)\\((.*?)\\)");
private static final Pattern PROPERTY_NAME_PATTERN = Pattern
.compile("\\s*(\\p{Alpha}\\w*)\\s*=(.+)");
private Construct compactConstruct;
protected Object constructCompactFormat(ScalarNode node, CompactData data) {
try {
Object obj = createInstance(node, data);
Map<String, Object> properties = new HashMap<String, Object>(data.getProperties());
setProperties(obj, properties);
return obj;
} catch (Exception e) {
throw new YAMLException(e);
}
}
protected Object createInstance(ScalarNode node, CompactData data) throws Exception {
Class<?> clazz = getClassForName(data.getPrefix());
Class<?>[] args = new Class[data.getArguments().size()];
for (int i = 0; i < args.length; i++) {
// assume all the arguments are Strings
args[i] = String.class;
}
java.lang.reflect.Constructor<?> c = clazz.getDeclaredConstructor(args);
c.setAccessible(true);
return c.newInstance(data.getArguments().toArray());
}
protected void setProperties(Object bean, Map<String, Object> data) throws Exception {
if (data == null) {
throw new NullPointerException("Data for Compact Object Notation cannot be null.");
}
for (Map.Entry<String, Object> entry : data.entrySet()) {
String key = entry.getKey();
Property property = getPropertyUtils().getProperty(bean.getClass(), key);
try {
property.set(bean, entry.getValue());
} catch (IllegalArgumentException e) {
throw new YAMLException("Cannot set property='" + key + "' with value='"
+ data.get(key) + "' (" + data.get(key).getClass() + ") in " + bean);
}
}
}
public CompactData getCompactData(String scalar) {
if (!scalar.endsWith(")")) {
return null;
}
if (scalar.indexOf('(') < 0) {
return null;
}
Matcher m = FIRST_PATTERN.matcher(scalar);
if (m.matches()) {
String tag = m.group(1).trim();
String content = m.group(3);
CompactData data = new CompactData(tag);
if (content.length() == 0)
return data;
String[] names = content.split("\\s*,\\s*");
for (int i = 0; i < names.length; i++) {
String section = names[i];
if (section.indexOf('=') < 0) {
data.getArguments().add(section);
} else {
Matcher sm = PROPERTY_NAME_PATTERN.matcher(section);
if (sm.matches()) {
String name = sm.group(1);
String value = sm.group(2).trim();
data.getProperties().put(name, value);
} else {
return null;
}
}
}
return data;
}
return null;
}
private Construct getCompactConstruct() {
if (compactConstruct == null) {
compactConstruct = createCompactConstruct();
}
return compactConstruct;
}
protected Construct createCompactConstruct() {
return new ConstructCompactObject();
}
@Override
protected Construct getConstructor(Node node) {
if (node instanceof MappingNode) {
MappingNode mnode = (MappingNode) node;
List<NodeTuple> list = mnode.getValue();
if (list.size() == 1) {
NodeTuple tuple = list.get(0);
Node key = tuple.getKeyNode();
if (key instanceof ScalarNode) {
ScalarNode scalar = (ScalarNode) key;
if (GUESS_COMPACT.matcher(scalar.getValue()).matches()) {
return getCompactConstruct();
}
}
}
} else if (node instanceof ScalarNode) {
ScalarNode scalar = (ScalarNode) node;
if (GUESS_COMPACT.matcher(scalar.getValue()).matches()) {
return getCompactConstruct();
}
}
return super.getConstructor(node);
}
public class ConstructCompactObject extends ConstructMapping {
@Override
public void construct2ndStep(Node node, Object object) {
// Compact Object Notation may contain only one entry
MappingNode mnode = (MappingNode) node;
NodeTuple nodeTuple = mnode.getValue().iterator().next();
Node valueNode = nodeTuple.getValueNode();
if (valueNode instanceof MappingNode) {
valueNode.setType(object.getClass());
constructJavaBean2ndStep((MappingNode) valueNode, object);
} else {
// value is a list
applySequence(object, constructSequence((SequenceNode) valueNode));
}
}
/*
* MappingNode and ScalarNode end up here only they assumed to be a
* compact object's representation (@see getConstructor(Node) above)
*/
public Object construct(Node node) {
ScalarNode tmpNode;
if (node instanceof MappingNode) {
// Compact Object Notation may contain only one entry
MappingNode mnode = (MappingNode) node;
NodeTuple nodeTuple = mnode.getValue().iterator().next();
node.setTwoStepsConstruction(true);
tmpNode = (ScalarNode) nodeTuple.getKeyNode();
// return constructScalar((ScalarNode) keyNode);
} else {
tmpNode = (ScalarNode) node;
}
CompactData data = getCompactData(tmpNode.getValue());
if (data == null) { // TODO: Should we throw an exception here ?
return constructScalar(tmpNode);
}
return constructCompactFormat(tmpNode, data);
}
}
protected void applySequence(Object bean, List<?> value) {
try {
Property property = getPropertyUtils().getProperty(bean.getClass(),
getSequencePropertyName(bean.getClass()));
property.set(bean, value);
} catch (Exception e) {
throw new YAMLException(e);
}
}
/**
* Provide the name of the property which is used when the entries form a
* sequence. The property must be a List.
* @param bean the class to provide exactly one List property
* @return name of the List property
*/
protected String getSequencePropertyName(Class<?> bean) {
Set<Property> properties = getPropertyUtils().getProperties(bean);
for (Iterator<Property> iterator = properties.iterator(); iterator.hasNext();) {
Property property = iterator.next();
if (!List.class.isAssignableFrom(property.getType())) {
iterator.remove();
}
}
if (properties.size() == 0) {
throw new YAMLException("No list property found in " + bean);
} else if (properties.size() > 1) {
throw new YAMLException(
"Many list properties found in "
+ bean
+ "; Please override getSequencePropertyName() to specify which property to use.");
}
return properties.iterator().next().getName();
}
}

View File

@ -0,0 +1,48 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.extensions.compactnotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CompactData {
private String prefix;
private List<String> arguments = new ArrayList<String>();
private Map<String, String> properties = new HashMap<String, String>();
public CompactData(String prefix) {
this.prefix = prefix;
}
public String getPrefix() {
return prefix;
}
public Map<String, String> getProperties() {
return properties;
}
public List<String> getArguments() {
return arguments;
}
@Override
public String toString() {
return "CompactData: " + prefix + " " + properties;
}
}

View File

@ -0,0 +1,37 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.extensions.compactnotation;
public class PackageCompactConstructor extends CompactConstructor {
private String packageName;
public PackageCompactConstructor(String packageName) {
this.packageName = packageName;
}
@Override
protected Class<?> getClassForName(String name) throws ClassNotFoundException {
if (name.indexOf('.') < 0) {
try {
Class<?> clazz = Class.forName(packageName + "." + name);
return clazz;
} catch (ClassNotFoundException e) {
// use super implementation
}
}
return super.getClassForName(name);
}
}

View File

@ -0,0 +1,305 @@
// Copyright 2003-2010 Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland
// www.source-code.biz, www.inventec.ch/chdh
//
// This module is multi-licensed and may be used under the terms
// of any of the following licenses:
//
// EPL, Eclipse Public License, V1.0 or later, http://www.eclipse.org/legal
// LGPL, GNU Lesser General Public License, V2.1 or later, http://www.gnu.org/licenses/lgpl.html
// GPL, GNU General Public License, V2 or later, http://www.gnu.org/licenses/gpl.html
// AL, Apache License, V2.0 or later, http://www.apache.org/licenses
// BSD, BSD License, http://www.opensource.org/licenses/bsd-license.php
//
// Please contact the author if you need another license.
// This module is provided "as is", without warranties of any kind.
package io.jenkins.plugins.casc.snakeyaml.external.biz.base64Coder;
/**
* A Base64 encoder/decoder.
*
* <p>
* This class is used to encode and decode data in Base64 format as described in
* RFC 1521.
*
* <p>
* Project home page: <a
* href="http://www.source-code.biz/base64coder/java/">www.
* source-code.biz/base64coder/java</a><br>
* Author: Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland<br>
* Multi-licensed: EPL / LGPL / GPL / AL / BSD.
*/
public class Base64Coder {
// The line separator string of the operating system.
private static final String systemLineSeparator = System.getProperty("line.separator");
// Mapping table from 6-bit nibbles to Base64 characters.
private static char[] map1 = new char[64];
static {
int i = 0;
for (char c = 'A'; c <= 'Z'; c++)
map1[i++] = c;
for (char c = 'a'; c <= 'z'; c++)
map1[i++] = c;
for (char c = '0'; c <= '9'; c++)
map1[i++] = c;
map1[i++] = '+';
map1[i++] = '/';
}
// Mapping table from Base64 characters to 6-bit nibbles.
private static byte[] map2 = new byte[128];
static {
for (int i = 0; i < map2.length; i++)
map2[i] = -1;
for (int i = 0; i < 64; i++)
map2[map1[i]] = (byte) i;
}
/**
* Encodes a string into Base64 format. No blanks or line breaks are
* inserted.
*
* @param s
* A String to be encoded.
* @return A String containing the Base64 encoded data.
*/
public static String encodeString(String s) {
return new String(encode(s.getBytes()));
}
/**
* Encodes a byte array into Base 64 format and breaks the output into lines
* of 76 characters. This method is compatible with
* <code>sun.misc.BASE64Encoder.encodeBuffer(byte[])</code>.
*
* @param in
* An array containing the data bytes to be encoded.
* @return A String containing the Base64 encoded data, broken into lines.
*/
public static String encodeLines(byte[] in) {
return encodeLines(in, 0, in.length, 76, systemLineSeparator);
}
/**
* Encodes a byte array into Base 64 format and breaks the output into
* lines.
*
* @param in
* An array containing the data bytes to be encoded.
* @param iOff
* Offset of the first byte in <code>in</code> to be processed.
* @param iLen
* Number of bytes to be processed in <code>in</code>, starting
* at <code>iOff</code>.
* @param lineLen
* Line length for the output data. Should be a multiple of 4.
* @param lineSeparator
* The line separator to be used to separate the output lines.
* @return A String containing the Base64 encoded data, broken into lines.
*/
public static String encodeLines(byte[] in, int iOff, int iLen, int lineLen,
String lineSeparator) {
int blockLen = (lineLen * 3) / 4;
if (blockLen <= 0)
throw new IllegalArgumentException();
int lines = (iLen + blockLen - 1) / blockLen;
int bufLen = ((iLen + 2) / 3) * 4 + lines * lineSeparator.length();
StringBuilder buf = new StringBuilder(bufLen);
int ip = 0;
while (ip < iLen) {
int l = Math.min(iLen - ip, blockLen);
buf.append(encode(in, iOff + ip, l));
buf.append(lineSeparator);
ip += l;
}
return buf.toString();
}
/**
* Encodes a byte array into Base64 format. No blanks or line breaks are
* inserted in the output.
*
* @param in
* An array containing the data bytes to be encoded.
* @return A character array containing the Base64 encoded data.
*/
public static char[] encode(byte[] in) {
return encode(in, 0, in.length);
}
/**
* Encodes a byte array into Base64 format. No blanks or line breaks are
* inserted in the output.
*
* @param in
* An array containing the data bytes to be encoded.
* @param iLen
* Number of bytes to process in <code>in</code>.
* @return A character array containing the Base64 encoded data.
*/
public static char[] encode(byte[] in, int iLen) {
return encode(in, 0, iLen);
}
/**
* Encodes a byte array into Base64 format. No blanks or line breaks are
* inserted in the output.
*
* @param in
* An array containing the data bytes to be encoded.
* @param iOff
* Offset of the first byte in <code>in</code> to be processed.
* @param iLen
* Number of bytes to process in <code>in</code>, starting at
* <code>iOff</code>.
* @return A character array containing the Base64 encoded data.
*/
public static char[] encode(byte[] in, int iOff, int iLen) {
int oDataLen = (iLen * 4 + 2) / 3; // output length without padding
int oLen = ((iLen + 2) / 3) * 4; // output length including padding
char[] out = new char[oLen];
int ip = iOff;
int iEnd = iOff + iLen;
int op = 0;
while (ip < iEnd) {
int i0 = in[ip++] & 0xff;
int i1 = ip < iEnd ? in[ip++] & 0xff : 0;
int i2 = ip < iEnd ? in[ip++] & 0xff : 0;
int o0 = i0 >>> 2;
int o1 = ((i0 & 3) << 4) | (i1 >>> 4);
int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
int o3 = i2 & 0x3F;
out[op++] = map1[o0];
out[op++] = map1[o1];
out[op] = op < oDataLen ? map1[o2] : '=';
op++;
out[op] = op < oDataLen ? map1[o3] : '=';
op++;
}
return out;
}
/**
* Decodes a string from Base64 format. No blanks or line breaks are allowed
* within the Base64 encoded input data.
*
* @param s
* A Base64 String to be decoded.
* @return A String containing the decoded data.
* @throws IllegalArgumentException
* If the input is not valid Base64 encoded data.
*/
public static String decodeString(String s) {
return new String(decode(s));
}
/**
* Decodes a byte array from Base64 format and ignores line separators, tabs
* and blanks. CR, LF, Tab and Space characters are ignored in the input
* data. This method is compatible with
* <code>sun.misc.BASE64Decoder.decodeBuffer(String)</code>.
*
* @param s
* A Base64 String to be decoded.
* @return An array containing the decoded data bytes.
* @throws IllegalArgumentException
* If the input is not valid Base64 encoded data.
*/
public static byte[] decodeLines(String s) {
char[] buf = new char[s.length()];
int p = 0;
for (int ip = 0; ip < s.length(); ip++) {
char c = s.charAt(ip);
if (c != ' ' && c != '\r' && c != '\n' && c != '\t')
buf[p++] = c;
}
return decode(buf, 0, p);
}
/**
* Decodes a byte array from Base64 format. No blanks or line breaks are
* allowed within the Base64 encoded input data.
*
* @param s
* A Base64 String to be decoded.
* @return An array containing the decoded data bytes.
* @throws IllegalArgumentException
* If the input is not valid Base64 encoded data.
*/
public static byte[] decode(String s) {
return decode(s.toCharArray());
}
/**
* Decodes a byte array from Base64 format. No blanks or line breaks are
* allowed within the Base64 encoded input data.
*
* @param in
* A character array containing the Base64 encoded data.
* @return An array containing the decoded data bytes.
* @throws IllegalArgumentException
* If the input is not valid Base64 encoded data.
*/
public static byte[] decode(char[] in) {
return decode(in, 0, in.length);
}
/**
* Decodes a byte array from Base64 format. No blanks or line breaks are
* allowed within the Base64 encoded input data.
*
* @param in
* A character array containing the Base64 encoded data.
* @param iOff
* Offset of the first character in <code>in</code> to be
* processed.
* @param iLen
* Number of characters to process in <code>in</code>, starting
* at <code>iOff</code>.
* @return An array containing the decoded data bytes.
* @throws IllegalArgumentException
* If the input is not valid Base64 encoded data.
*/
public static byte[] decode(char[] in, int iOff, int iLen) {
if (iLen % 4 != 0)
throw new IllegalArgumentException(
"Length of Base64 encoded input string is not a multiple of 4.");
while (iLen > 0 && in[iOff + iLen - 1] == '=')
iLen--;
int oLen = (iLen * 3) / 4;
byte[] out = new byte[oLen];
int ip = iOff;
int iEnd = iOff + iLen;
int op = 0;
while (ip < iEnd) {
int i0 = in[ip++];
int i1 = in[ip++];
int i2 = ip < iEnd ? in[ip++] : 'A';
int i3 = ip < iEnd ? in[ip++] : 'A';
if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127)
throw new IllegalArgumentException("Illegal character in Base64 encoded data.");
int b0 = map2[i0];
int b1 = map2[i1];
int b2 = map2[i2];
int b3 = map2[i3];
if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0)
throw new IllegalArgumentException("Illegal character in Base64 encoded data.");
int o0 = (b0 << 2) | (b1 >>> 4);
int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2);
int o2 = ((b2 & 3) << 6) | b3;
out[op++] = (byte) o0;
if (op < oLen)
out[op++] = (byte) o1;
if (op < oLen)
out[op++] = (byte) o2;
}
return out;
}
// Dummy constructor.
private Base64Coder() {
}
} // end class Base64Coder

View File

@ -0,0 +1,97 @@
/* Copyright (c) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.external.com.google.gdata.util.common.base;
/**
* An object that converts literal text into a format safe for inclusion in a
* particular context (such as an XML document). Typically (but not always), the
* inverse process of "unescaping" the text is performed automatically by the
* relevant parser.
*
* <p>
* For example, an XML escaper would convert the literal string
* {@code "Foo<Bar>"} into {@code "Foo&lt;Bar&gt;"} to prevent {@code "<Bar>"}
* from being confused with an XML tag. When the resulting XML document is
* parsed, the parser API will return this text as the original literal string
* {@code "Foo<Bar>"}.
*
* <p>
* An {@code Escaper} instance is required to be stateless, and safe when used
* concurrently by multiple threads.
*
* <p>
* Several popular escapers are defined as constants in the class
* {@link CharEscapers}. To create your own escapers, use
* {@link CharEscaperBuilder}, or extend {@link CharEscaper} or
* {@code UnicodeEscaper}.
*
*
*/
public interface Escaper {
/**
* Returns the escaped form of a given literal string.
*
* <p>
* Note that this method may treat input characters differently depending on
* the specific escaper implementation.
* <ul>
* <li>{@link UnicodeEscaper} handles <a
* href="http://en.wikipedia.org/wiki/UTF-16">UTF-16</a> correctly,
* including surrogate character pairs. If the input is badly formed the
* escaper should throw {@link IllegalArgumentException}.
* <li>{@link CharEscaper} handles Java characters independently and does
* not verify the input for well formed characters. A CharEscaper should not
* be used in situations where input is not guaranteed to be restricted to
* the Basic Multilingual Plane (BMP).
* </ul>
*
* @param string
* the literal string to be escaped
* @return the escaped form of {@code string}
* @throws NullPointerException
* if {@code string} is null
* @throws IllegalArgumentException
* if {@code string} contains badly formed UTF-16 or cannot be
* escaped for any other reason
*/
public String escape(String string);
/**
* Returns an {@code Appendable} instance which automatically escapes all
* text appended to it before passing the resulting text to an underlying
* {@code Appendable}.
*
* <p>
* Note that this method may treat input characters differently depending on
* the specific escaper implementation.
* <ul>
* <li>{@link UnicodeEscaper} handles <a
* href="http://en.wikipedia.org/wiki/UTF-16">UTF-16</a> correctly,
* including surrogate character pairs. If the input is badly formed the
* escaper should throw {@link IllegalArgumentException}.
* <li>{@link CharEscaper} handles Java characters independently and does
* not verify the input for well formed characters. A CharEscaper should not
* be used in situations where input is not guaranteed to be restricted to
* the Basic Multilingual Plane (BMP).
* </ul>
*
* @param out
* the underlying {@code Appendable} to append escaped output to
* @return an {@code Appendable} which passes text to {@code out} after
* escaping it.
*/
public Appendable escape(Appendable out);
}

View File

@ -0,0 +1,281 @@
/* Copyright (c) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.external.com.google.gdata.util.common.base;
/**
* A {@code UnicodeEscaper} that escapes some set of Java characters using the
* URI percent encoding scheme. The set of safe characters (those which remain
* unescaped) can be specified on construction.
*
* <p>
* For details on escaping URIs for use in web pages, see section 2.4 of <a
* href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
*
* <p>
* In most cases this class should not need to be used directly. If you have no
* special requirements for escaping your URIs, you should use either
* {@link CharEscapers#uriEscaper()} or {@link CharEscapers#uriEscaper(boolean)}.
*
* <p>
* When encoding a String, the following rules apply:
* <ul>
* <li>The alphanumeric characters "a" through "z", "A" through "Z" and "0"
* through "9" remain the same.
* <li>Any additionally specified safe characters remain the same.
* <li>If {@code plusForSpace} was specified, the space character " " is
* converted into a plus sign "+".
* <li>All other characters are converted into one or more bytes using UTF-8
* encoding and each byte is then represented by the 3-character string "%XY",
* where "XY" is the two-digit, uppercase, hexadecimal representation of the
* byte value.
* </ul>
*
* <p>
* RFC 2396 specifies the set of unreserved characters as "-", "_", ".", "!",
* "~", "*", "'", "(" and ")". It goes on to state:
*
* <p>
* <i>Unreserved characters can be escaped without changing the semantics of the
* URI, but this should not be done unless the URI is being used in a context
* that does not allow the unescaped character to appear.</i>
*
* <p>
* For performance reasons the only currently supported character encoding of
* this class is UTF-8.
*
* <p>
* <b>Note</b>: This escaper produces uppercase hexidecimal sequences. From <a
* href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>:<br>
* <i>"URI producers and normalizers should use uppercase hexadecimal digits for
* all percent-encodings."</i>
*
*
*/
public class PercentEscaper extends UnicodeEscaper {
/**
* A string of safe characters that mimics the behavior of
* {@link java.net.URLEncoder}.
*
*/
public static final String SAFECHARS_URLENCODER = "-_.*";
/**
* A string of characters that do not need to be encoded when used in URI
* path segments, as specified in RFC 3986. Note that some of these
* characters do need to be escaped when used in other parts of the URI.
*/
public static final String SAFEPATHCHARS_URLENCODER = "-_.!~*'()@:$&,;=";
/**
* A string of characters that do not need to be encoded when used in URI
* query strings, as specified in RFC 3986. Note that some of these
* characters do need to be escaped when used in other parts of the URI.
*/
public static final String SAFEQUERYSTRINGCHARS_URLENCODER = "-_.!~*'()@:$,;/?:";
// In some uri escapers spaces are escaped to '+'
private static final char[] URI_ESCAPED_SPACE = { '+' };
private static final char[] UPPER_HEX_DIGITS = "0123456789ABCDEF".toCharArray();
/**
* If true we should convert space to the {@code +} character.
*/
private final boolean plusForSpace;
/**
* An array of flags where for any {@code char c} if {@code safeOctets[c]}
* is true then {@code c} should remain unmodified in the output. If
* {@code c > safeOctets.length} then it should be escaped.
*/
private final boolean[] safeOctets;
/**
* Constructs a URI escaper with the specified safe characters and optional
* handling of the space character.
*
* @param safeChars
* a non null string specifying additional safe characters for
* this escaper (the ranges 0..9, a..z and A..Z are always safe
* and should not be specified here)
* @param plusForSpace
* true if ASCII space should be escaped to {@code +} rather than
* {@code %20}
* @throws IllegalArgumentException
* if any of the parameters were invalid
*/
public PercentEscaper(String safeChars, boolean plusForSpace) {
// Avoid any misunderstandings about the behavior of this escaper
if (safeChars.matches(".*[0-9A-Za-z].*")) {
throw new IllegalArgumentException(
"Alphanumeric characters are always 'safe' and should not be "
+ "explicitly specified");
}
// Avoid ambiguous parameters. Safe characters are never modified so if
// space is a safe character then setting plusForSpace is meaningless.
if (plusForSpace && safeChars.contains(" ")) {
throw new IllegalArgumentException(
"plusForSpace cannot be specified when space is a 'safe' character");
}
if (safeChars.contains("%")) {
throw new IllegalArgumentException("The '%' character cannot be specified as 'safe'");
}
this.plusForSpace = plusForSpace;
this.safeOctets = createSafeOctets(safeChars);
}
/**
* Creates a boolean[] with entries corresponding to the character values
* for 0-9, A-Z, a-z and those specified in safeChars set to true. The array
* is as small as is required to hold the given character information.
*/
private static boolean[] createSafeOctets(String safeChars) {
int maxChar = 'z';
char[] safeCharArray = safeChars.toCharArray();
for (char c : safeCharArray) {
maxChar = Math.max(c, maxChar);
}
boolean[] octets = new boolean[maxChar + 1];
for (int c = '0'; c <= '9'; c++) {
octets[c] = true;
}
for (int c = 'A'; c <= 'Z'; c++) {
octets[c] = true;
}
for (int c = 'a'; c <= 'z'; c++) {
octets[c] = true;
}
for (char c : safeCharArray) {
octets[c] = true;
}
return octets;
}
/*
* Overridden for performance. For unescaped strings this improved the
* performance of the uri escaper from ~760ns to ~400ns as measured by
* {@link CharEscapersBenchmark}.
*/
@Override
protected int nextEscapeIndex(CharSequence csq, int index, int end) {
for (; index < end; index++) {
char c = csq.charAt(index);
if (c >= safeOctets.length || !safeOctets[c]) {
break;
}
}
return index;
}
/*
* Overridden for performance. For unescaped strings this improved the
* performance of the uri escaper from ~400ns to ~170ns as measured by
* {@link CharEscapersBenchmark}.
*/
@Override
public String escape(String s) {
int slen = s.length();
for (int index = 0; index < slen; index++) {
char c = s.charAt(index);
if (c >= safeOctets.length || !safeOctets[c]) {
return escapeSlow(s, index);
}
}
return s;
}
/**
* Escapes the given Unicode code point in UTF-8.
*/
@Override
protected char[] escape(int cp) {
// We should never get negative values here but if we do it will throw
// an
// IndexOutOfBoundsException, so at least it will get spotted.
if (cp < safeOctets.length && safeOctets[cp]) {
return null;
} else if (cp == ' ' && plusForSpace) {
return URI_ESCAPED_SPACE;
} else if (cp <= 0x7F) {
// Single byte UTF-8 characters
// Start with "%--" and fill in the blanks
char[] dest = new char[3];
dest[0] = '%';
dest[2] = UPPER_HEX_DIGITS[cp & 0xF];
dest[1] = UPPER_HEX_DIGITS[cp >>> 4];
return dest;
} else if (cp <= 0x7ff) {
// Two byte UTF-8 characters [cp >= 0x80 && cp <= 0x7ff]
// Start with "%--%--" and fill in the blanks
char[] dest = new char[6];
dest[0] = '%';
dest[3] = '%';
dest[5] = UPPER_HEX_DIGITS[cp & 0xF];
cp >>>= 4;
dest[4] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
cp >>>= 2;
dest[2] = UPPER_HEX_DIGITS[cp & 0xF];
cp >>>= 4;
dest[1] = UPPER_HEX_DIGITS[0xC | cp];
return dest;
} else if (cp <= 0xffff) {
// Three byte UTF-8 characters [cp >= 0x800 && cp <= 0xffff]
// Start with "%E-%--%--" and fill in the blanks
char[] dest = new char[9];
dest[0] = '%';
dest[1] = 'E';
dest[3] = '%';
dest[6] = '%';
dest[8] = UPPER_HEX_DIGITS[cp & 0xF];
cp >>>= 4;
dest[7] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
cp >>>= 2;
dest[5] = UPPER_HEX_DIGITS[cp & 0xF];
cp >>>= 4;
dest[4] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
cp >>>= 2;
dest[2] = UPPER_HEX_DIGITS[cp];
return dest;
} else if (cp <= 0x10ffff) {
char[] dest = new char[12];
// Four byte UTF-8 characters [cp >= 0xffff && cp <= 0x10ffff]
// Start with "%F-%--%--%--" and fill in the blanks
dest[0] = '%';
dest[1] = 'F';
dest[3] = '%';
dest[6] = '%';
dest[9] = '%';
dest[11] = UPPER_HEX_DIGITS[cp & 0xF];
cp >>>= 4;
dest[10] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
cp >>>= 2;
dest[8] = UPPER_HEX_DIGITS[cp & 0xF];
cp >>>= 4;
dest[7] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
cp >>>= 2;
dest[5] = UPPER_HEX_DIGITS[cp & 0xF];
cp >>>= 4;
dest[4] = UPPER_HEX_DIGITS[0x8 | (cp & 0x3)];
cp >>>= 2;
dest[2] = UPPER_HEX_DIGITS[cp & 0x7];
return dest;
} else {
// If this ever happens it is due to bug in UnicodeEscaper, not bad
// input.
throw new IllegalArgumentException("Invalid unicode character value " + cp);
}
}
}

View File

@ -0,0 +1,506 @@
/* Copyright (c) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.external.com.google.gdata.util.common.base;
import java.io.IOException;
/**
* An {@link Escaper} that converts literal text into a format safe for
* inclusion in a particular context (such as an XML document). Typically (but
* not always), the inverse process of "unescaping" the text is performed
* automatically by the relevant parser.
*
* <p>
* For example, an XML escaper would convert the literal string
* {@code "Foo<Bar>"} into {@code "Foo&lt;Bar&gt;"} to prevent {@code "<Bar>"}
* from being confused with an XML tag. When the resulting XML document is
* parsed, the parser API will return this text as the original literal string
* {@code "Foo<Bar>"}.
*
* <p>
* <b>Note:</b> This class is similar to {@link CharEscaper} but with one very
* important difference. A CharEscaper can only process Java <a
* href="http://en.wikipedia.org/wiki/UTF-16">UTF16</a> characters in isolation
* and may not cope when it encounters surrogate pairs. This class facilitates
* the correct escaping of all Unicode characters.
*
* <p>
* As there are important reasons, including potential security issues, to
* handle Unicode correctly if you are considering implementing a new escaper
* you should favor using UnicodeEscaper wherever possible.
*
* <p>
* A {@code UnicodeEscaper} instance is required to be stateless, and safe when
* used concurrently by multiple threads.
*
* <p>
* Several popular escapers are defined as constants in the class
* {@link CharEscapers}. To create your own escapers extend this class and
* implement the {@link #escape(int)} method.
*
*
*/
public abstract class UnicodeEscaper implements Escaper {
/** The amount of padding (chars) to use when growing the escape buffer. */
private static final int DEST_PAD = 32;
/**
* Returns the escaped form of the given Unicode code point, or {@code null}
* if this code point does not need to be escaped. When called as part of an
* escaping operation, the given code point is guaranteed to be in the range
* {@code 0 <= cp <= Character#MAX_CODE_POINT}.
*
* <p>
* If an empty array is returned, this effectively strips the input
* character from the resulting text.
*
* <p>
* If the character does not need to be escaped, this method should return
* {@code null}, rather than an array containing the character
* representation of the code point. This enables the escaping algorithm to
* perform more efficiently.
*
* <p>
* If the implementation of this method cannot correctly handle a particular
* code point then it should either throw an appropriate runtime exception
* or return a suitable replacement character. It must never silently
* discard invalid input as this may constitute a security risk.
*
* @param cp
* the Unicode code point to escape if necessary
* @return the replacement characters, or {@code null} if no escaping was
* needed
*/
protected abstract char[] escape(int cp);
/**
* Scans a sub-sequence of characters from a given {@link CharSequence},
* returning the index of the next character that requires escaping.
*
* <p>
* <b>Note:</b> When implementing an escaper, it is a good idea to override
* this method for efficiency. The base class implementation determines
* successive Unicode code points and invokes {@link #escape(int)} for each
* of them. If the semantics of your escaper are such that code points in
* the supplementary range are either all escaped or all unescaped, this
* method can be implemented more efficiently using
* {@link CharSequence#charAt(int)}.
*
* <p>
* Note however that if your escaper does not escape characters in the
* supplementary range, you should either continue to validate the
* correctness of any surrogate characters encountered or provide a clear
* warning to users that your escaper does not validate its input.
*
* <p>
* See {@link PercentEscaper} for an example.
*
* @param csq
* a sequence of characters
* @param start
* the index of the first character to be scanned
* @param end
* the index immediately after the last character to be scanned
* @throws IllegalArgumentException
* if the scanned sub-sequence of {@code csq} contains invalid
* surrogate pairs
*/
protected int nextEscapeIndex(CharSequence csq, int start, int end) {
int index = start;
while (index < end) {
int cp = codePointAt(csq, index, end);
if (cp < 0 || escape(cp) != null) {
break;
}
index += Character.isSupplementaryCodePoint(cp) ? 2 : 1;
}
return index;
}
/**
* Returns the escaped form of a given literal string.
*
* <p>
* If you are escaping input in arbitrary successive chunks, then it is not
* generally safe to use this method. If an input string ends with an
* unmatched high surrogate character, then this method will throw
* {@link IllegalArgumentException}. You should either ensure your input is
* valid <a href="http://en.wikipedia.org/wiki/UTF-16">UTF-16</a> before
* calling this method or use an escaped {@link Appendable} (as returned by
* {@link #escape(Appendable)}) which can cope with arbitrarily split input.
*
* <p>
* <b>Note:</b> When implementing an escaper it is a good idea to override
* this method for efficiency by inlining the implementation of
* {@link #nextEscapeIndex(CharSequence, int, int)} directly. Doing this for
* {@link PercentEscaper} more than doubled the performance for unescaped
* strings (as measured by {@link CharEscapersBenchmark}).
*
* @param string
* the literal string to be escaped
* @return the escaped form of {@code string}
* @throws NullPointerException
* if {@code string} is null
* @throws IllegalArgumentException
* if invalid surrogate characters are encountered
*/
public String escape(String string) {
int end = string.length();
int index = nextEscapeIndex(string, 0, end);
return index == end ? string : escapeSlow(string, index);
}
/**
* Returns the escaped form of a given literal string, starting at the given
* index. This method is called by the {@link #escape(String)} method when
* it discovers that escaping is required. It is protected to allow
* subclasses to override the fastpath escaping function to inline their
* escaping test. See {@link CharEscaperBuilder} for an example usage.
*
* <p>
* This method is not reentrant and may only be invoked by the top level
* {@link #escape(String)} method.
*
* @param s
* the literal string to be escaped
* @param index
* the index to start escaping from
* @return the escaped form of {@code string}
* @throws NullPointerException
* if {@code string} is null
* @throws IllegalArgumentException
* if invalid surrogate characters are encountered
*/
protected final String escapeSlow(String s, int index) {
int end = s.length();
// Get a destination buffer and setup some loop variables.
char[] dest = DEST_TL.get();
int destIndex = 0;
int unescapedChunkStart = 0;
while (index < end) {
int cp = codePointAt(s, index, end);
if (cp < 0) {
throw new IllegalArgumentException("Trailing high surrogate at end of input");
}
char[] escaped = escape(cp);
if (escaped != null) {
int charsSkipped = index - unescapedChunkStart;
// This is the size needed to add the replacement, not the full
// size needed by the string. We only regrow when we absolutely
// must.
int sizeNeeded = destIndex + charsSkipped + escaped.length;
if (dest.length < sizeNeeded) {
int destLength = sizeNeeded + (end - index) + DEST_PAD;
dest = growBuffer(dest, destIndex, destLength);
}
// If we have skipped any characters, we need to copy them now.
if (charsSkipped > 0) {
s.getChars(unescapedChunkStart, index, dest, destIndex);
destIndex += charsSkipped;
}
if (escaped.length > 0) {
System.arraycopy(escaped, 0, dest, destIndex, escaped.length);
destIndex += escaped.length;
}
}
unescapedChunkStart = index + (Character.isSupplementaryCodePoint(cp) ? 2 : 1);
index = nextEscapeIndex(s, unescapedChunkStart, end);
}
// Process trailing unescaped characters - no need to account for
// escaped
// length or padding the allocation.
int charsSkipped = end - unescapedChunkStart;
if (charsSkipped > 0) {
int endIndex = destIndex + charsSkipped;
if (dest.length < endIndex) {
dest = growBuffer(dest, destIndex, endIndex);
}
s.getChars(unescapedChunkStart, end, dest, destIndex);
destIndex = endIndex;
}
return new String(dest, 0, destIndex);
}
/**
* Returns an {@code Appendable} instance which automatically escapes all
* text appended to it before passing the resulting text to an underlying
* {@code Appendable}.
*
* <p>
* Unlike {@link #escape(String)} it is permitted to append arbitrarily
* split input to this Appendable, including input that is split over a
* surrogate pair. In this case the pending high surrogate character will
* not be processed until the corresponding low surrogate is appended. This
* means that a trailing high surrogate character at the end of the input
* cannot be detected and will be silently ignored. This is unavoidable
* since the Appendable interface has no {@code close()} method, and it is
* impossible to determine when the last characters have been appended.
*
* <p>
* The methods of the returned object will propagate any exceptions thrown
* by the underlying {@code Appendable}.
*
* <p>
* For well formed <a href="http://en.wikipedia.org/wiki/UTF-16">UTF-16</a>
* the escaping behavior is identical to that of {@link #escape(String)} and
* the following code is equivalent to (but much slower than)
* {@code escaper.escape(string)}:
*
* <pre>
* {
* &#064;code
* StringBuilder sb = new StringBuilder();
* escaper.escape(sb).append(string);
* return sb.toString();
* }
* </pre>
*
* @param out
* the underlying {@code Appendable} to append escaped output to
* @return an {@code Appendable} which passes text to {@code out} after
* escaping it
* @throws NullPointerException
* if {@code out} is null
* @throws IllegalArgumentException
* if invalid surrogate characters are encountered
*
*/
public Appendable escape(final Appendable out) {
assert out != null;
return new Appendable() {
int pendingHighSurrogate = -1;
char[] decodedChars = new char[2];
public Appendable append(CharSequence csq) throws IOException {
return append(csq, 0, csq.length());
}
public Appendable append(CharSequence csq, int start, int end) throws IOException {
int index = start;
if (index < end) {
// This is a little subtle: index must never reference the
// middle of a
// surrogate pair but unescapedChunkStart can. The first
// time we enter
// the loop below it is possible that index !=
// unescapedChunkStart.
int unescapedChunkStart = index;
if (pendingHighSurrogate != -1) {
// Our last append operation ended halfway through a
// surrogate pair
// so we have to do some extra work first.
char c = csq.charAt(index++);
if (!Character.isLowSurrogate(c)) {
throw new IllegalArgumentException(
"Expected low surrogate character but got " + c);
}
char[] escaped = escape(Character.toCodePoint((char) pendingHighSurrogate,
c));
if (escaped != null) {
// Emit the escaped character and adjust
// unescapedChunkStart to
// skip the low surrogate we have consumed.
outputChars(escaped, escaped.length);
unescapedChunkStart += 1;
} else {
// Emit pending high surrogate (unescaped) but do
// not modify
// unescapedChunkStart as we must still emit the low
// surrogate.
out.append((char) pendingHighSurrogate);
}
pendingHighSurrogate = -1;
}
while (true) {
// Find and append the next subsequence of unescaped
// characters.
index = nextEscapeIndex(csq, index, end);
if (index > unescapedChunkStart) {
out.append(csq, unescapedChunkStart, index);
}
if (index == end) {
break;
}
// If we are not finished, calculate the next code
// point.
int cp = codePointAt(csq, index, end);
if (cp < 0) {
// Our sequence ended half way through a surrogate
// pair so just
// record the state and exit.
pendingHighSurrogate = -cp;
break;
}
// Escape the code point and output the characters.
char[] escaped = escape(cp);
if (escaped != null) {
outputChars(escaped, escaped.length);
} else {
// This shouldn't really happen if nextEscapeIndex
// is correct but
// we should cope with false positives.
int len = Character.toChars(cp, decodedChars, 0);
outputChars(decodedChars, len);
}
// Update our index past the escaped character and
// continue.
index += (Character.isSupplementaryCodePoint(cp) ? 2 : 1);
unescapedChunkStart = index;
}
}
return this;
}
public Appendable append(char c) throws IOException {
if (pendingHighSurrogate != -1) {
// Our last append operation ended halfway through a
// surrogate pair
// so we have to do some extra work first.
if (!Character.isLowSurrogate(c)) {
throw new IllegalArgumentException(
"Expected low surrogate character but got '" + c + "' with value "
+ (int) c);
}
char[] escaped = escape(Character.toCodePoint((char) pendingHighSurrogate, c));
if (escaped != null) {
outputChars(escaped, escaped.length);
} else {
out.append((char) pendingHighSurrogate);
out.append(c);
}
pendingHighSurrogate = -1;
} else if (Character.isHighSurrogate(c)) {
// This is the start of a (split) surrogate pair.
pendingHighSurrogate = c;
} else {
if (Character.isLowSurrogate(c)) {
throw new IllegalArgumentException("Unexpected low surrogate character '"
+ c + "' with value " + (int) c);
}
// This is a normal (non surrogate) char.
char[] escaped = escape(c);
if (escaped != null) {
outputChars(escaped, escaped.length);
} else {
out.append(c);
}
}
return this;
}
private void outputChars(char[] chars, int len) throws IOException {
for (int n = 0; n < len; n++) {
out.append(chars[n]);
}
}
};
}
/**
* Returns the Unicode code point of the character at the given index.
*
* <p>
* Unlike {@link Character#codePointAt(CharSequence, int)} or
* {@link String#codePointAt(int)} this method will never fail silently when
* encountering an invalid surrogate pair.
*
* <p>
* The behaviour of this method is as follows:
* <ol>
* <li>If {@code index >= end}, {@link IndexOutOfBoundsException} is thrown.
* <li><b>If the character at the specified index is not a surrogate, it is
* returned.</b>
* <li>If the first character was a high surrogate value, then an attempt is
* made to read the next character.
* <ol>
* <li><b>If the end of the sequence was reached, the negated value of the
* trailing high surrogate is returned.</b>
* <li><b>If the next character was a valid low surrogate, the code point
* value of the high/low surrogate pair is returned.</b>
* <li>If the next character was not a low surrogate value, then
* {@link IllegalArgumentException} is thrown.
* </ol>
* <li>If the first character was a low surrogate value,
* {@link IllegalArgumentException} is thrown.
* </ol>
*
* @param seq
* the sequence of characters from which to decode the code point
* @param index
* the index of the first character to decode
* @param end
* the index beyond the last valid character to decode
* @return the Unicode code point for the given index or the negated value
* of the trailing high surrogate character at the end of the
* sequence
*/
protected static final int codePointAt(CharSequence seq, int index, int end) {
if (index < end) {
char c1 = seq.charAt(index++);
if (c1 < Character.MIN_HIGH_SURROGATE || c1 > Character.MAX_LOW_SURROGATE) {
// Fast path (first test is probably all we need to do)
return c1;
} else if (c1 <= Character.MAX_HIGH_SURROGATE) {
// If the high surrogate was the last character, return its
// inverse
if (index == end) {
return -c1;
}
// Otherwise look for the low surrogate following it
char c2 = seq.charAt(index);
if (Character.isLowSurrogate(c2)) {
return Character.toCodePoint(c1, c2);
}
throw new IllegalArgumentException("Expected low surrogate but got char '" + c2
+ "' with value " + (int) c2 + " at index " + index);
} else {
throw new IllegalArgumentException("Unexpected low surrogate character '" + c1
+ "' with value " + (int) c1 + " at index " + (index - 1));
}
}
throw new IndexOutOfBoundsException("Index exceeds specified range");
}
/**
* Helper method to grow the character buffer as needed, this only happens
* once in a while so it's ok if it's in a method call. If the index passed
* in is 0 then no copying will be done.
*/
private static final char[] growBuffer(char[] dest, int index, int size) {
char[] copy = new char[size];
if (index > 0) {
System.arraycopy(dest, 0, copy, 0, index);
}
return copy;
}
/**
* A thread-local destination buffer to keep us from creating new buffers.
* The starting size is 1024 characters. If we grow past this we don't put
* it back in the threadlocal, we just keep going and grow as needed.
*/
private static final ThreadLocal<char[]> DEST_TL = new ThreadLocal<char[]>() {
@Override
protected char[] initialValue() {
return new char[1024];
}
};
}

View File

@ -0,0 +1,30 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.introspector;
/**
* Control instance variables.
*/
public enum BeanAccess {
/** use JavaBean properties and public fields */
DEFAULT,
/** use all declared fields (including inherited) */
FIELD,
/** reserved */
PROPERTY;
}

View File

@ -0,0 +1,67 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.introspector;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.List;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
import io.jenkins.plugins.casc.snakeyaml.util.ArrayUtils;
/**
* <p>
* A <code>FieldProperty</code> is a <code>Property</code> which is accessed as
* a field, without going through accessor methods (setX, getX). The field may
* have any scope (public, package, protected, private).
* </p>
*/
public class FieldProperty extends GenericProperty {
private final Field field;
public FieldProperty(Field field) {
super(field.getName(), field.getType(), field.getGenericType());
this.field = field;
field.setAccessible(true);
}
@Override
public void set(Object object, Object value) throws Exception {
field.set(object, value);
}
@Override
public Object get(Object object) {
try {
return field.get(object);
} catch (Exception e) {
throw new YAMLException("Unable to access field " + field.getName() + " on object "
+ object + " : " + e);
}
}
@Override
public List<Annotation> getAnnotations() {
return ArrayUtils.toUnmodifiableList(field.getAnnotations());
}
@Override
public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
return field.getAnnotation(annotationType);
}
}

View File

@ -0,0 +1,82 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.introspector;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
abstract public class GenericProperty extends Property {
private Type genType;
public GenericProperty(String name, Class<?> aClass, Type aType) {
super(name, aClass);
genType = aType;
actualClassesChecked = aType == null;
}
private boolean actualClassesChecked;
private Class<?>[] actualClasses;
public Class<?>[] getActualTypeArguments() { // should we synchronize here ?
if (!actualClassesChecked) {
if (genType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genType;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
if (actualTypeArguments.length > 0) {
actualClasses = new Class<?>[actualTypeArguments.length];
for (int i = 0; i < actualTypeArguments.length; i++) {
if (actualTypeArguments[i] instanceof Class<?>) {
actualClasses[i] = (Class<?>) actualTypeArguments[i];
} else if (actualTypeArguments[i] instanceof ParameterizedType) {
actualClasses[i] = (Class<?>) ((ParameterizedType) actualTypeArguments[i])
.getRawType();
} else if (actualTypeArguments[i] instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) actualTypeArguments[i])
.getGenericComponentType();
if (componentType instanceof Class<?>) {
actualClasses[i] = Array.newInstance((Class<?>) componentType, 0)
.getClass();
} else {
actualClasses = null;
break;
}
} else {
actualClasses = null;
break;
}
}
}
} else if (genType instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) genType).getGenericComponentType();
if (componentType instanceof Class<?>) {
actualClasses = new Class<?>[] { (Class<?>) componentType };
}
} else if (genType instanceof Class<?>) {// XXX this check is only
// required for IcedTea6
Class<?> classType = (Class<?>) genType;
if (classType.isArray()) {
actualClasses = new Class<?>[1];
actualClasses[0] = getType().getComponentType();
}
}
actualClassesChecked = true;
}
return actualClasses;
}
}

View File

@ -0,0 +1,139 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.introspector;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.util.List;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
import io.jenkins.plugins.casc.snakeyaml.util.ArrayUtils;
/**
* <p>
* A <code>MethodProperty</code> is a <code>Property</code> which is accessed
* through accessor methods (setX, getX). It is possible to have a
* <code>MethodProperty</code> which has only setter, only getter, or both. It
* is not possible to have a <code>MethodProperty</code> which has neither
* setter nor getter.
* </p>
*/
public class MethodProperty extends GenericProperty {
private final PropertyDescriptor property;
private final boolean readable;
private final boolean writable;
private static Type discoverGenericType(PropertyDescriptor property) {
Method readMethod = property.getReadMethod();
if (readMethod != null) {
return readMethod.getGenericReturnType();
}
Method writeMethod = property.getWriteMethod();
if (writeMethod != null) {
Type[] paramTypes = writeMethod.getGenericParameterTypes();
if (paramTypes.length > 0) {
return paramTypes[0];
}
}
/*
* This actually may happen if PropertyDescriptor is of type
* IndexedPropertyDescriptor and it has only IndexedGetter/Setter. ATM
* we simply skip type discovery.
*/
return null;
}
public MethodProperty(PropertyDescriptor property) {
super(property.getName(), property.getPropertyType(),
MethodProperty.discoverGenericType(property));
this.property = property;
this.readable = property.getReadMethod() != null;
this.writable = property.getWriteMethod() != null;
}
@Override
public void set(Object object, Object value) throws Exception {
if (!writable) {
throw new YAMLException("No writable property '" + getName() + "' on class: "
+ object.getClass().getName());
}
property.getWriteMethod().invoke(object, value);
}
@Override
public Object get(Object object) {
try {
property.getReadMethod().setAccessible(true);// issue 50
return property.getReadMethod().invoke(object);
} catch (Exception e) {
throw new YAMLException("Unable to find getter for property '" + property.getName()
+ "' on object " + object + ":" + e);
}
}
/**
* Returns the annotations that are present on read and write methods of this property or empty {@code List} if
* there're no annotations.
*
* @return the annotations that are present on this property or empty {@code List} if there're no annotations
*/
@Override
public List<Annotation> getAnnotations() {
List<Annotation> annotations;
if (isReadable() && isWritable()) {
annotations = ArrayUtils.toUnmodifiableCompositeList(property.getReadMethod().getAnnotations(), property.getWriteMethod().getAnnotations());
} else if (isReadable()) {
annotations = ArrayUtils.toUnmodifiableList(property.getReadMethod().getAnnotations());
} else {
annotations = ArrayUtils.toUnmodifiableList(property.getWriteMethod().getAnnotations());
}
return annotations;
}
/**
* Returns property's annotation for the given type or {@code null} if it's not present. If the annotation is present
* on both read and write methods, the annotation on read method takes precedence.
*
* @param annotationType the type of the annotation to be returned
* @return property's annotation for the given type or {@code null} if it's not present
*/
@Override
public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
A annotation = null;
if (isReadable()) {
annotation = property.getReadMethod().getAnnotation(annotationType);
}
if (annotation == null && isWritable()) {
annotation = property.getWriteMethod().getAnnotation(annotationType);
}
return annotation;
}
@Override
public boolean isWritable() {
return writable;
}
@Override
public boolean isReadable() {
return readable;
}
}

View File

@ -0,0 +1,59 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.introspector;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.List;
/**
* A property that does not map to a real property; this is used when {@link
* PropertyUtils}.setSkipMissingProperties(boolean) is set to true.
*/
public class MissingProperty extends Property {
public MissingProperty(String name) {
super(name, Object.class);
}
@Override
public Class<?>[] getActualTypeArguments() {
return new Class[0];
}
/**
* Setter does nothing.
*/
@Override
public void set(Object object, Object value) throws Exception {
}
@Override
public Object get(Object object) {
return object;
}
@Override
public List<Annotation> getAnnotations() {
return Collections.emptyList();
}
@Override
public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
return null;
}
}

View File

@ -0,0 +1,105 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.introspector;
import java.lang.annotation.Annotation;
import java.util.List;
/**
* <p>
* A <code>Property</code> represents a single member variable of a class,
* possibly including its accessor methods (getX, setX). The name stored in this
* class is the actual name of the property as given for the class, not an
* alias.
* </p>
*
* <p>
* Objects of this class have a total ordering which defaults to ordering based
* on the name of the property.
* </p>
*/
public abstract class Property implements Comparable<Property> {
private final String name;
private final Class<?> type;
public Property(String name, Class<?> type) {
this.name = name;
this.type = type;
}
public Class<?> getType() {
return type;
}
abstract public Class<?>[] getActualTypeArguments();
public String getName() {
return name;
}
@Override
public String toString() {
return getName() + " of " + getType();
}
public int compareTo(Property o) {
return getName().compareTo(o.getName());
}
public boolean isWritable() {
return true;
}
public boolean isReadable() {
return true;
}
abstract public void set(Object object, Object value) throws Exception;
abstract public Object get(Object object);
/**
* Returns the annotations that are present on this property or empty {@code List} if there're no annotations.
*
* @return the annotations that are present on this property or empty {@code List} if there're no annotations
*/
abstract public List<Annotation> getAnnotations();
/**
* Returns property's annotation for the given type or {@code null} if it's not present.
*
* @param annotationType the type of the annotation to be returned
* @param <A> class of the annotation
*
* @return property's annotation for the given type or {@code null} if it's not present
*/
abstract public <A extends Annotation> A getAnnotation(Class<A> annotationType);
@Override
public int hashCode() {
return getName().hashCode() + getType().hashCode();
}
@Override
public boolean equals(Object other) {
if (other instanceof Property) {
Property p = (Property) other;
return getName().equals(p.getName()) && getType().equals(p.getType());
}
return false;
}
}

View File

@ -0,0 +1,258 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.introspector;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
// TODO: decide priorities for get/set Read/Field/Delegate Write/Field/Delegate - is FIELD on the correct place ?
public class PropertySubstitute extends Property {
final private static Logger log = Logger.getLogger(PropertySubstitute.class.getPackage()
.getName());
protected Class<?> targetType;
private final String readMethod;
private final String writeMethod;
transient private Method read;
transient private Method write;
private Field field;
protected Class<?>[] parameters;
private Property delegate;
private boolean filler;
public PropertySubstitute(String name, Class<?> type, String readMethod, String writeMethod,
Class<?>... params) {
super(name, type);
this.readMethod = readMethod;
this.writeMethod = writeMethod;
setActualTypeArguments(params);
this.filler = false;
}
public PropertySubstitute(String name, Class<?> type, Class<?>... params) {
this(name, type, null, null, params);
}
@Override
public Class<?>[] getActualTypeArguments() {
if (parameters == null && delegate != null) {
return delegate.getActualTypeArguments();
}
return parameters;
}
public void setActualTypeArguments(Class<?>... args) {
if (args != null && args.length > 0) {
parameters = args;
} else {
parameters = null;
}
}
@Override
public void set(Object object, Object value) throws Exception {
if (write != null) {
if (!filler) {
write.invoke(object, value);
} else if (value != null) {
if (value instanceof Collection<?>) {
Collection<?> collection = (Collection<?>) value;
for (Object val : collection) {
write.invoke(object, val);
}
} else if (value instanceof Map<?, ?>) {
Map<?, ?> map = (Map<?, ?>) value;
for (Entry<?, ?> entry : map.entrySet()) {
write.invoke(object, entry.getKey(), entry.getValue());
}
} else if (value.getClass().isArray()) { // TODO: maybe arrays
// need 2 fillers like
// SET(index, value)
// add ADD(value)
int len = Array.getLength(value);
for (int i = 0; i < len; i++) {
write.invoke(object, Array.get(value, i));
}
}
}
} else if (field != null) {
field.set(object, value);
} else if (delegate != null) {
delegate.set(object, value);
} else {
log.warning("No setter/delegate for '" + getName() + "' on object " + object);
}
// TODO: maybe throw YAMLException here
}
@Override
public Object get(Object object) {
try {
if (read != null) {
return read.invoke(object);
} else if (field != null) {
return field.get(object);
}
} catch (Exception e) {
throw new YAMLException("Unable to find getter for property '" + getName()
+ "' on object " + object + ":" + e);
}
if (delegate != null) {
return delegate.get(object);
}
throw new YAMLException("No getter or delegate for property '" + getName() + "' on object "
+ object);
}
@Override
public List<Annotation> getAnnotations() {
Annotation[] annotations = null;
if (read != null) {
annotations = read.getAnnotations();
} else if (field != null) {
annotations = field.getAnnotations();
}
return annotations != null ? Arrays.asList(annotations) : delegate.getAnnotations();
}
@Override
public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
A annotation;
if (read != null) {
annotation = read.getAnnotation(annotationType);
} else if (field != null) {
annotation = field.getAnnotation(annotationType);
} else {
annotation = delegate.getAnnotation(annotationType);
}
return annotation;
}
public void setTargetType(Class<?> targetType) {
if (this.targetType != targetType) {
this.targetType = targetType;
final String name = getName();
for (Class<?> c = targetType; c != null; c = c.getSuperclass()) {
for (Field f : c.getDeclaredFields()) {
if (f.getName().equals(name)) {
int modifiers = f.getModifiers();
if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)) {
f.setAccessible(true);
field = f;
}
break;
}
}
}
if (field == null && log.isLoggable(Level.FINE)) {
log.fine(String.format("Failed to find field for %s.%s", targetType.getName(),
getName()));
}
// Retrieve needed info
if (readMethod != null) {
read = discoverMethod(targetType, readMethod);
}
if (writeMethod != null) {
filler = false;
write = discoverMethod(targetType, writeMethod, getType());
if (write == null && parameters != null) {
filler = true;
write = discoverMethod(targetType, writeMethod, parameters);
}
}
}
}
private Method discoverMethod(Class<?> type, String name, Class<?>... params) {
for (Class<?> c = type; c != null; c = c.getSuperclass()) {
for (Method method : c.getDeclaredMethods()) {
if (name.equals(method.getName())) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != params.length) {
continue;
}
boolean found = true;
for (int i = 0; i < parameterTypes.length; i++) {
if (!parameterTypes[i].isAssignableFrom(params[i])) {
found = false;
}
}
if (found) {
method.setAccessible(true);
return method;
}
}
}
}
if (log.isLoggable(Level.FINE)) {
log.fine(String.format("Failed to find [%s(%d args)] for %s.%s", name, params.length,
targetType.getName(), getName()));
}
return null;
}
@Override
public String getName() {
final String n = super.getName();
if (n != null) {
return n;
}
return delegate != null ? delegate.getName() : null;
}
@Override
public Class<?> getType() {
final Class<?> t = super.getType();
if (t != null) {
return t;
}
return delegate != null ? delegate.getType() : null;
}
@Override
public boolean isReadable() {
return (read != null) || (field != null) || (delegate != null && delegate.isReadable());
}
@Override
public boolean isWritable() {
return (write != null) || (field != null) || (delegate != null && delegate.isWritable());
}
public void setDelegate(Property delegate) {
this.delegate = delegate;
if (writeMethod != null && write == null && !filler) {
filler = true;
write = discoverMethod(targetType, writeMethod, getActualTypeArguments());
}
}
}

View File

@ -0,0 +1,205 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.introspector;
import java.beans.FeatureDescriptor;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
import io.jenkins.plugins.casc.snakeyaml.util.PlatformFeatureDetector;
public class PropertyUtils {
private final Map<Class<?>, Map<String, Property>> propertiesCache = new HashMap<Class<?>, Map<String, Property>>();
private final Map<Class<?>, Set<Property>> readableProperties = new HashMap<Class<?>, Set<Property>>();
private BeanAccess beanAccess = BeanAccess.DEFAULT;
private boolean allowReadOnlyProperties = false;
private boolean skipMissingProperties = false;
private PlatformFeatureDetector platformFeatureDetector;
public PropertyUtils() {
this(new PlatformFeatureDetector());
}
PropertyUtils(PlatformFeatureDetector platformFeatureDetector) {
this.platformFeatureDetector = platformFeatureDetector;
/*
* Android lacks much of java.beans (including the Introspector class, used here), because java.beans classes tend to rely on java.awt, which isn't
* supported in the Android SDK. That means we have to fall back on FIELD access only when SnakeYAML is running on the Android Runtime.
*/
if (platformFeatureDetector.isRunningOnAndroid()) {
beanAccess = BeanAccess.FIELD;
}
}
protected Map<String, Property> getPropertiesMap(Class<?> type, BeanAccess bAccess) {
if (propertiesCache.containsKey(type)) {
return propertiesCache.get(type);
}
Map<String, Property> properties = new LinkedHashMap<String, Property>();
boolean inaccessableFieldsExist = false;
switch (bAccess) {
case FIELD:
for (Class<?> c = type; c != null; c = c.getSuperclass()) {
for (Field field : c.getDeclaredFields()) {
int modifiers = field.getModifiers();
if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)
&& !properties.containsKey(field.getName())) {
properties.put(field.getName(), new FieldProperty(field));
}
}
}
break;
default:
// add JavaBean properties
try {
for (PropertyDescriptor property : Introspector.getBeanInfo(type)
.getPropertyDescriptors()) {
Method readMethod = property.getReadMethod();
if ((readMethod == null || !readMethod.getName().equals("getClass"))
&& !isTransient(property)) {
properties.put(property.getName(), new MethodProperty(property));
}
}
} catch (IntrospectionException e) {
throw new YAMLException(e);
}
// add public fields
for (Class<?> c = type; c != null; c = c.getSuperclass()) {
for (Field field : c.getDeclaredFields()) {
int modifiers = field.getModifiers();
if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)) {
if (Modifier.isPublic(modifiers)) {
properties.put(field.getName(), new FieldProperty(field));
} else {
inaccessableFieldsExist = true;
}
}
}
}
break;
}
if (properties.isEmpty() && inaccessableFieldsExist) {
throw new YAMLException("No JavaBean properties found in " + type.getName());
}
propertiesCache.put(type, properties);
return properties;
}
private static final String TRANSIENT = "transient";
private boolean isTransient(FeatureDescriptor fd) {
return Boolean.TRUE.equals(fd.getValue(TRANSIENT));
}
public Set<Property> getProperties(Class<? extends Object> type) {
return getProperties(type, beanAccess);
}
public Set<Property> getProperties(Class<? extends Object> type, BeanAccess bAccess) {
if (readableProperties.containsKey(type)) {
return readableProperties.get(type);
}
Set<Property> properties = createPropertySet(type, bAccess);
readableProperties.put(type, properties);
return properties;
}
protected Set<Property> createPropertySet(Class<? extends Object> type, BeanAccess bAccess) {
Set<Property> properties = new TreeSet<Property>();
Collection<Property> props = getPropertiesMap(type, bAccess).values();
for (Property property : props) {
if (property.isReadable() && (allowReadOnlyProperties || property.isWritable())) {
properties.add(property);
}
}
return properties;
}
public Property getProperty(Class<? extends Object> type, String name) {
return getProperty(type, name, beanAccess);
}
public Property getProperty(Class<? extends Object> type, String name, BeanAccess bAccess) {
Map<String, Property> properties = getPropertiesMap(type, bAccess);
Property property = properties.get(name);
if (property == null && skipMissingProperties) {
property = new MissingProperty(name);
}
if (property == null) {
throw new YAMLException(
"Unable to find property '" + name + "' on class: " + type.getName());
}
return property;
}
public void setBeanAccess(BeanAccess beanAccess) {
if (platformFeatureDetector.isRunningOnAndroid() && beanAccess != BeanAccess.FIELD) {
throw new IllegalArgumentException(
"JVM is Android - only BeanAccess.FIELD is available");
}
if (this.beanAccess != beanAccess) {
this.beanAccess = beanAccess;
propertiesCache.clear();
readableProperties.clear();
}
}
public void setAllowReadOnlyProperties(boolean allowReadOnlyProperties) {
if (this.allowReadOnlyProperties != allowReadOnlyProperties) {
this.allowReadOnlyProperties = allowReadOnlyProperties;
readableProperties.clear();
}
}
public boolean isAllowReadOnlyProperties() {
return allowReadOnlyProperties;
}
/**
* Skip properties that are missing during deserialization of YAML to a Java
* object. The default is false.
*
* @param skipMissingProperties
* true if missing properties should be skipped, false otherwise.
*/
public void setSkipMissingProperties(boolean skipMissingProperties) {
if (this.skipMissingProperties != skipMissingProperties) {
this.skipMissingProperties = skipMissingProperties;
readableProperties.clear();
}
}
public boolean isSkipMissingProperties() {
return skipMissingProperties;
}
}

View File

@ -0,0 +1,35 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.nodes;
public class AnchorNode extends Node {
private Node realNode;
public AnchorNode(Node realNode) {
super(realNode.getTag(), realNode.getStartMark(), realNode.getEndMark());
this.realNode = realNode;
}
@Override
public NodeId getNodeId() {
return NodeId.anchor;
}
public Node getRealNode() {
return realNode;
}
}

View File

@ -0,0 +1,70 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.nodes;
import java.util.List;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Base class for the two collection types {@link MappingNode mapping} and
* {@link SequenceNode collection}.
*/
public abstract class CollectionNode<T> extends Node {
private DumperOptions.FlowStyle flowStyle;
public CollectionNode(Tag tag, Mark startMark, Mark endMark, DumperOptions.FlowStyle flowStyle) {
super(tag, startMark, endMark);
setFlowStyle(flowStyle);
}
/*
* Existed in older versions but replaced with {@link DumperOptions.FlowStyle}-based constructor.
* Restored in v1.22 for backwards compatibility.
* @deprecated Since restored in v1.22. Use {@link CollectionNode#CollectionNode(Tag, Mark, Mark, io.jenkins.plugins.casc.snakeyaml.DumperOptions.FlowStyle) }.
*/
@Deprecated
public CollectionNode(Tag tag, Mark startMark, Mark endMark, Boolean flowStyle) {
this(tag, startMark, endMark, DumperOptions.FlowStyle.fromBoolean(flowStyle));
}
/**
* Returns the elements in this sequence.
*
* @return Nodes in the specified order.
*/
abstract public List<T> getValue();
/**
* Serialization style of this collection.
*
* @return <code>true</code> for flow style, <code>false</code> for block
* style.
*/
public DumperOptions.FlowStyle getFlowStyle() {
return flowStyle;
}
public void setFlowStyle(DumperOptions.FlowStyle flowStyle) {
if (flowStyle == null) throw new NullPointerException("Flow style must be provided.");
this.flowStyle = flowStyle;
}
public void setEndMark(Mark endMark) {
this.endMark = endMark;
}
}

View File

@ -0,0 +1,134 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.nodes;
import java.util.List;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Represents a map.
* <p>
* A map is a collection of unsorted key-value pairs.
* </p>
*/
public class MappingNode extends CollectionNode<NodeTuple> {
private List<NodeTuple> value;
private boolean merged = false;
public MappingNode(Tag tag, boolean resolved, List<NodeTuple> value, Mark startMark,
Mark endMark, DumperOptions.FlowStyle flowStyle) {
super(tag, startMark, endMark, flowStyle);
if (value == null) {
throw new NullPointerException("value in a Node is required.");
}
this.value = value;
this.resolved = resolved;
}
public MappingNode(Tag tag, List<NodeTuple> value, DumperOptions.FlowStyle flowStyle) {
this(tag, true, value, null, null, flowStyle);
}
/*
* Existed in older versions but replaced with {@link DumperOptions.FlowStyle}-based constructor.
* Restored in v1.22 for backwards compatibility.
* @deprecated Since restored in v1.22. Use {@link MappingNode#MappingNode(Tag, boolean, List, Mark, Mark, io.jenkins.plugins.casc.snakeyaml.DumperOptions.FlowStyle) }.
*/
@Deprecated
public MappingNode(Tag tag, boolean resolved, List<NodeTuple> value, Mark startMark,
Mark endMark, Boolean flowStyle) {
this(tag, resolved, value, startMark, endMark, DumperOptions.FlowStyle.fromBoolean(flowStyle));
}
/*
* Existed in older versions but replaced with {@link DumperOptions.FlowStyle}-based constructor.
* Restored in v1.22 for backwards compatibility.
* @deprecated Since restored in v1.22. Use {@link MappingNode#MappingNode(Tag, List, io.jenkins.plugins.casc.snakeyaml.DumperOptions.FlowStyle) }.
*/
@Deprecated
public MappingNode(Tag tag, List<NodeTuple> value, Boolean flowStyle) {
this(tag, value, DumperOptions.FlowStyle.fromBoolean(flowStyle));
}
@Override
public NodeId getNodeId() {
return NodeId.mapping;
}
/**
* Returns the entries of this map.
*
* @return List of entries.
*/
public List<NodeTuple> getValue() {
return value;
}
public void setValue(List<NodeTuple> mergedValue) {
value = mergedValue;
}
public void setOnlyKeyType(Class<? extends Object> keyType) {
for (NodeTuple nodes : value) {
nodes.getKeyNode().setType(keyType);
}
}
public void setTypes(Class<? extends Object> keyType, Class<? extends Object> valueType) {
for (NodeTuple nodes : value) {
nodes.getValueNode().setType(valueType);
nodes.getKeyNode().setType(keyType);
}
}
@Override
public String toString() {
String values;
StringBuilder buf = new StringBuilder();
for (NodeTuple node : getValue()) {
buf.append("{ key=");
buf.append(node.getKeyNode());
buf.append("; value=");
if (node.getValueNode() instanceof CollectionNode) {
// to avoid overflow in case of recursive structures
buf.append(System.identityHashCode(node.getValueNode()));
} else {
buf.append(node.toString());
}
buf.append(" }");
}
values = buf.toString();
return "<" + this.getClass().getName() + " (tag=" + getTag() + ", values=" + values + ")>";
}
/**
* @param merged
* - true if map contains merge node
*/
public void setMerged(boolean merged) {
this.merged = merged;
}
/**
* @return true if map contains merge node
*/
public boolean isMerged() {
return merged;
}
}

View File

@ -0,0 +1,168 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.nodes;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Base class for all nodes.
* <p>
* The nodes form the node-graph described in the <a
* href="http://yaml.org/spec/1.1/">YAML Specification</a>.
* </p>
* <p>
* While loading, the node graph is usually created by the
* {@link io.jenkins.plugins.casc.snakeyaml.composer.Composer}, and later transformed into
* application specific Java classes by the classes from the
* {@link io.jenkins.plugins.casc.snakeyaml.constructor} package.
* </p>
*/
public abstract class Node {
private Tag tag;
private Mark startMark;
protected Mark endMark;
private Class<? extends Object> type;
private boolean twoStepsConstruction;
/**
* true when the tag is assigned by the resolver
*/
protected boolean resolved;
protected Boolean useClassConstructor;
public Node(Tag tag, Mark startMark, Mark endMark) {
setTag(tag);
this.startMark = startMark;
this.endMark = endMark;
this.type = Object.class;
this.twoStepsConstruction = false;
this.resolved = true;
this.useClassConstructor = null;
}
/**
* Tag of this node.
* <p>
* Every node has a tag assigned. The tag is either local or global.
*
* @return Tag of this node.
*/
public Tag getTag() {
return this.tag;
}
public Mark getEndMark() {
return endMark;
}
/**
* @return scalar, sequence, mapping
*/
public abstract NodeId getNodeId();
public Mark getStartMark() {
return startMark;
}
public void setTag(Tag tag) {
if (tag == null) {
throw new NullPointerException("tag in a Node is required.");
}
this.tag = tag;
}
/**
* Node is only equal to itself
*/
@Override
public final boolean equals(Object obj) {
return super.equals(obj);
}
public Class<? extends Object> getType() {
return type;
}
public void setType(Class<? extends Object> type) {
if (!type.isAssignableFrom(this.type)) {
this.type = type;
}
}
public void setTwoStepsConstruction(boolean twoStepsConstruction) {
this.twoStepsConstruction = twoStepsConstruction;
}
/**
* Indicates if this node must be constructed in two steps.
* <p>
* Two-step construction is required whenever a node is a child (direct or
* indirect) of it self. That is, if a recursive structure is build using
* anchors and aliases.
* </p>
* <p>
* Set by {@link io.jenkins.plugins.casc.snakeyaml.composer.Composer}, used during the
* construction process.
* </p>
* <p>
* Only relevant during loading.
* </p>
*
* @return <code>true</code> if the node is self referenced.
*/
public boolean isTwoStepsConstruction() {
return twoStepsConstruction;
}
@Override
public final int hashCode() {
return super.hashCode();
}
public boolean useClassConstructor() {
if (useClassConstructor == null) {
if (!tag.isSecondary() && resolved && !Object.class.equals(type)
&& !tag.equals(Tag.NULL)) {
return true;
} else if (tag.isCompatible(getType())) {
// the tag is compatible with the runtime class
// the tag will be ignored
return true;
} else {
return false;
}
}
return useClassConstructor.booleanValue();
}
public void setUseClassConstructor(Boolean useClassConstructor) {
this.useClassConstructor = useClassConstructor;
}
/**
* Indicates if the tag was added by
* {@link io.jenkins.plugins.casc.snakeyaml.resolver.Resolver}.
*
* @return true if the tag of this node was resolved
*
* @deprecated Since v1.22. Absent in immediately prior versions, but present previously. Restored deprecated for backwards compatibility.
*/
@Deprecated
public boolean isResolved() {
return resolved;
}
}

View File

@ -0,0 +1,23 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.nodes;
/**
* Enum for the basic YAML types: scalar, sequence, mapping or anchor.
*/
public enum NodeId {
scalar, sequence, mapping, anchor
}

View File

@ -0,0 +1,57 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.nodes;
/**
* Stores one key value pair used in a map.
*/
public final class NodeTuple {
private Node keyNode;
private Node valueNode;
public NodeTuple(Node keyNode, Node valueNode) {
if (keyNode == null || valueNode == null) {
throw new NullPointerException("Nodes must be provided.");
}
this.keyNode = keyNode;
this.valueNode = valueNode;
}
/**
* Key node.
*
* @return the node used as key
*/
public Node getKeyNode() {
return keyNode;
}
/**
* Value node.
*
* @return node used as value
*/
public Node getValueNode() {
return valueNode;
}
@Override
public String toString() {
return "<NodeTuple keyNode=" + keyNode.toString() + "; valueNode=" + valueNode.toString()
+ ">";
}
}

View File

@ -0,0 +1,116 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.nodes;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Represents a scalar node.
* <p>
* Scalar nodes form the leaves in the node graph.
* </p>
*/
public class ScalarNode extends Node {
private DumperOptions.ScalarStyle style;
private String value;
public ScalarNode(Tag tag, String value, Mark startMark, Mark endMark, DumperOptions.ScalarStyle style) {
this(tag, true, value, startMark, endMark, style);
}
public ScalarNode(Tag tag, boolean resolved, String value, Mark startMark, Mark endMark,
DumperOptions.ScalarStyle style) {
super(tag, startMark, endMark);
if (value == null) {
throw new NullPointerException("value in a Node is required.");
}
this.value = value;
if (style == null) throw new NullPointerException("Scalar style must be provided.");
this.style = style;
this.resolved = resolved;
}
/*
* Existed in older versions but replaced with {@link DumperOptions.ScalarStyle}-based constructor.
* Restored in v1.22 for backwards compatibility.
* @deprecated Since restored in v1.22. Use {@link ScalarNode#ScalarNode(Tag, String, Mark, Mark, io.jenkins.plugins.casc.snakeyaml.DumperOptions.ScalarStyle) }.
*/
@Deprecated
public ScalarNode(Tag tag, String value, Mark startMark, Mark endMark, Character style) {
this(tag, value, startMark, endMark, DumperOptions.ScalarStyle.createStyle(style));
}
/*
* Existed in older versions but replaced with {@link DumperOptions.ScalarStyle}-based constructor.
* Restored in v1.22 for backwards compatibility.
* @deprecated Since restored in v1.22. Use {@link ScalarNode#ScalarNode(Tag, boolean, String, Mark, Mark, io.jenkins.plugins.casc.snakeyaml.DumperOptions.ScalarStyle) }.
*/
@Deprecated
public ScalarNode(Tag tag, boolean resolved, String value, Mark startMark, Mark endMark,
Character style) {
this(tag, resolved, value, startMark, endMark, DumperOptions.ScalarStyle.createStyle(style));
}
/**
* Get scalar style of this node.
*
* @see io.jenkins.plugins.casc.snakeyaml.events.ScalarEvent
* @see <a href="http://yaml.org/spec/1.1/#id903915">Chapter 9. Scalar
* Styles</a>
* @return style of this scalar node
* @deprecated use getScalarStyle instead
*/
@Deprecated
public Character getStyle() {
return style.getChar();
}
/**
* Get scalar style of this node.
*
* @see io.jenkins.plugins.casc.snakeyaml.events.ScalarEvent
* @see <a href="http://yaml.org/spec/1.1/#id903915">Chapter 9. Scalar
* Styles</a>
* @return style of this scalar node
*/
public DumperOptions.ScalarStyle getScalarStyle() {
return style;
}
@Override
public NodeId getNodeId() {
return NodeId.scalar;
}
/**
* Value of this scalar.
*
* @return Scalar's value.
*/
public String getValue() {
return value;
}
public String toString() {
return "<" + this.getClass().getName() + " (tag=" + getTag() + ", value=" + getValue()
+ ")>";
}
public boolean isPlain() {
return style == DumperOptions.ScalarStyle.PLAIN;
}
}

View File

@ -0,0 +1,91 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.nodes;
import java.util.List;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Represents a sequence.
* <p>
* A sequence is a ordered collection of nodes.
* </p>
*/
public class SequenceNode extends CollectionNode<Node> {
final private List<Node> value;
public SequenceNode(Tag tag, boolean resolved, List<Node> value, Mark startMark, Mark endMark,
DumperOptions.FlowStyle flowStyle) {
super(tag, startMark, endMark, flowStyle);
if (value == null) {
throw new NullPointerException("value in a Node is required.");
}
this.value = value;
this.resolved = resolved;
}
public SequenceNode(Tag tag, List<Node> value, DumperOptions.FlowStyle flowStyle) {
this(tag, true, value, null, null, flowStyle);
}
/*
* Existed in older versions but replaced with {@link DumperOptions.SequenceStyle}-based constructor.
* Restored in v1.22 for backwards compatibility.
* @deprecated Since restored in v1.22. Use {@link SequenceNode#SequenceNode(Tag, List<Node>, io.jenkins.plugins.casc.snakeyaml.DumperOptions.FlowStyle) }.
*/
@Deprecated
public SequenceNode(Tag tag, List<Node> value, Boolean style) {
this(tag, value, DumperOptions.FlowStyle.fromBoolean(style));
}
/*
* Existed in older versions but replaced with {@link DumperOptions.SequenceStyle}-based constructor.
* Restored in v1.22 for backwards compatibility.
* @deprecated Since restored in v1.22. Use {@link SequenceNode#SequenceNode(Tag, boolean, List<Node>, Mark, Mark, io.jenkins.plugins.casc.snakeyaml.DumperOptions.FlowStyle) }.
*/
@Deprecated
public SequenceNode(Tag tag, boolean resolved, List<Node> value, Mark startMark, Mark endMark,
Boolean style) {
this(tag, resolved, value, startMark, endMark, DumperOptions.FlowStyle.fromBoolean(style));
}
@Override
public NodeId getNodeId() {
return NodeId.sequence;
}
/**
* Returns the elements in this sequence.
*
* @return Nodes in the specified order.
*/
public List<Node> getValue() {
return value;
}
public void setListType(Class<? extends Object> listType) {
for (Node node : value) {
node.setType(listType);
}
}
public String toString() {
return "<" + this.getClass().getName() + " (tag=" + getTag() + ", value=" + getValue()
+ ")>";
}
}

View File

@ -0,0 +1,168 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.nodes;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URI;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
import io.jenkins.plugins.casc.snakeyaml.util.UriEncoder;
public final class Tag {
public static final String PREFIX = "tag:yaml.org,2002:";
public static final Tag YAML = new Tag(PREFIX + "yaml");
public static final Tag MERGE = new Tag(PREFIX + "merge");
public static final Tag SET = new Tag(PREFIX + "set");
public static final Tag PAIRS = new Tag(PREFIX + "pairs");
public static final Tag OMAP = new Tag(PREFIX + "omap");
public static final Tag BINARY = new Tag(PREFIX + "binary");
public static final Tag INT = new Tag(PREFIX + "int");
public static final Tag FLOAT = new Tag(PREFIX + "float");
public static final Tag TIMESTAMP = new Tag(PREFIX + "timestamp");
public static final Tag BOOL = new Tag(PREFIX + "bool");
public static final Tag NULL = new Tag(PREFIX + "null");
public static final Tag STR = new Tag(PREFIX + "str");
public static final Tag SEQ = new Tag(PREFIX + "seq");
public static final Tag MAP = new Tag(PREFIX + "map");
public static final Map<Tag, Set<Class<?>>> COMPATIBILITY_MAP;
static {
COMPATIBILITY_MAP = new HashMap<Tag, Set<Class<?>>>();
Set<Class<?>> floatSet = new HashSet<Class<?>>();
floatSet.add(Double.class);
floatSet.add(Float.class);
floatSet.add(BigDecimal.class);
COMPATIBILITY_MAP.put(FLOAT, floatSet);
//
Set<Class<?>> intSet = new HashSet<Class<?>>();
intSet.add(Integer.class);
intSet.add(Long.class);
intSet.add(BigInteger.class);
COMPATIBILITY_MAP.put(INT, intSet);
//
Set<Class<?>> timestampSet = new HashSet<Class<?>>();
timestampSet.add(Date.class);
timestampSet.add(java.sql.Date.class);
timestampSet.add(Timestamp.class);
COMPATIBILITY_MAP.put(TIMESTAMP, timestampSet);
}
private final String value;
private boolean secondary = false; // see http://www.yaml.org/refcard.html
public Tag(String tag) {
if (tag == null) {
throw new NullPointerException("Tag must be provided.");
} else if (tag.length() == 0) {
throw new IllegalArgumentException("Tag must not be empty.");
} else if (tag.trim().length() != tag.length()) {
throw new IllegalArgumentException("Tag must not contain leading or trailing spaces.");
}
this.value = UriEncoder.encode(tag);
this.secondary = !tag.startsWith(PREFIX);
}
public Tag(Class<? extends Object> clazz) {
if (clazz == null) {
throw new NullPointerException("Class for tag must be provided.");
}
this.value = Tag.PREFIX + UriEncoder.encode(clazz.getName());
}
/**
* @deprecated - it will be removed
* @param uri - URI to be encoded as tag value
*/
public Tag(URI uri) {
if (uri == null) {
throw new NullPointerException("URI for tag must be provided.");
}
this.value = uri.toASCIIString();
}
public boolean isSecondary() {
return secondary;
}
public String getValue() {
return value;
}
public boolean startsWith(String prefix) {
return value.startsWith(prefix);
}
public String getClassName() {
if (!value.startsWith(Tag.PREFIX)) {
throw new YAMLException("Invalid tag: " + value);
}
return UriEncoder.decode(value.substring(Tag.PREFIX.length()));
}
@Override
public String toString() {
return value;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Tag) {
return value.equals(((Tag) obj).getValue());
} else
return false;
}
@Override
public int hashCode() {
return value.hashCode();
}
/**
* Java has more then 1 class compatible with a language-independent tag
* (!!int, !!float, !!timestamp etc)
*
* @param clazz
* - Class to check compatibility
* @return true when the Class can be represented by this
* language-independent tag
*/
public boolean isCompatible(Class<?> clazz) {
Set<Class<?>> set = COMPATIBILITY_MAP.get(this);
if (set != null) {
return set.contains(clazz);
} else {
return false;
}
}
/**
* Check whether this tag matches the global tag for the Class
*
* @param clazz
* - Class to check
* @return true when the this tag can be used as a global tag for the Class
*/
public boolean matches(Class<? extends Object> clazz) {
return value.equals(Tag.PREFIX + clazz.getName());
}
}

View File

@ -0,0 +1,65 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.parser;
import io.jenkins.plugins.casc.snakeyaml.events.Event;
/**
* This interface represents an input stream of {@link Event Events}.
* <p>
* The parser and the scanner form together the 'Parse' step in the loading
* process (see chapter 3.1 of the <a href="http://yaml.org/spec/1.1/">YAML
* Specification</a>).
* </p>
*
* @see io.jenkins.plugins.casc.snakeyaml.events.Event
*/
public interface Parser {
/**
* Check if the next event is one of the given type.
*
* @param choice
* Event ID.
* @return <code>true</code> if the next event can be assigned to a variable
* of the given type. Returns <code>false</code> if no more events
* are available.
* @throws ParserException
* Thrown in case of malformed input.
*/
public boolean checkEvent(Event.ID choice);
/**
* Return the next event, but do not delete it from the stream.
*
* @return The event that will be returned on the next call to
* {@link #getEvent}
* @throws ParserException
* Thrown in case of malformed input.
*/
public Event peekEvent();
/**
* Returns the next event.
* <p>
* The event will be removed from the stream.
* </p>
* @return the next parsed event
* @throws ParserException
* Thrown in case of malformed input.
*/
public Event getEvent();
}

View File

@ -0,0 +1,44 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.parser;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
import io.jenkins.plugins.casc.snakeyaml.error.MarkedYAMLException;
/**
* Exception thrown by the {@link Parser} implementations in case of malformed
* input.
*/
public class ParserException extends MarkedYAMLException {
private static final long serialVersionUID = -2349253802798398038L;
/**
* Constructs an instance.
*
* @param context
* Part of the input document in which vicinity the problem
* occurred.
* @param contextMark
* Position of the <code>context</code> within the document.
* @param problem
* Part of the input document that caused the problem.
* @param problemMark
* Position of the <code>problem</code>. within the document.
*/
public ParserException(String context, Mark contextMark, String problem, Mark problemMark) {
super(context, contextMark, problem, problemMark, null, null);
}
}

View File

@ -0,0 +1,795 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.parser;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions.Version;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
import io.jenkins.plugins.casc.snakeyaml.events.AliasEvent;
import io.jenkins.plugins.casc.snakeyaml.events.DocumentEndEvent;
import io.jenkins.plugins.casc.snakeyaml.events.DocumentStartEvent;
import io.jenkins.plugins.casc.snakeyaml.events.Event;
import io.jenkins.plugins.casc.snakeyaml.events.ImplicitTuple;
import io.jenkins.plugins.casc.snakeyaml.events.MappingEndEvent;
import io.jenkins.plugins.casc.snakeyaml.events.MappingStartEvent;
import io.jenkins.plugins.casc.snakeyaml.events.ScalarEvent;
import io.jenkins.plugins.casc.snakeyaml.events.SequenceEndEvent;
import io.jenkins.plugins.casc.snakeyaml.events.SequenceStartEvent;
import io.jenkins.plugins.casc.snakeyaml.events.StreamEndEvent;
import io.jenkins.plugins.casc.snakeyaml.events.StreamStartEvent;
import io.jenkins.plugins.casc.snakeyaml.nodes.Tag;
import io.jenkins.plugins.casc.snakeyaml.reader.StreamReader;
import io.jenkins.plugins.casc.snakeyaml.scanner.Scanner;
import io.jenkins.plugins.casc.snakeyaml.scanner.ScannerImpl;
import io.jenkins.plugins.casc.snakeyaml.tokens.AliasToken;
import io.jenkins.plugins.casc.snakeyaml.tokens.AnchorToken;
import io.jenkins.plugins.casc.snakeyaml.tokens.BlockEntryToken;
import io.jenkins.plugins.casc.snakeyaml.tokens.DirectiveToken;
import io.jenkins.plugins.casc.snakeyaml.tokens.ScalarToken;
import io.jenkins.plugins.casc.snakeyaml.tokens.StreamEndToken;
import io.jenkins.plugins.casc.snakeyaml.tokens.StreamStartToken;
import io.jenkins.plugins.casc.snakeyaml.tokens.TagToken;
import io.jenkins.plugins.casc.snakeyaml.tokens.TagTuple;
import io.jenkins.plugins.casc.snakeyaml.tokens.Token;
import io.jenkins.plugins.casc.snakeyaml.util.ArrayStack;
/**
* <pre>
* # The following YAML grammar is LL(1) and is parsed by a recursive descent
* parser.
* stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
* implicit_document ::= block_node DOCUMENT-END*
* explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
* block_node_or_indentless_sequence ::=
* ALIAS
* | properties (block_content | indentless_block_sequence)?
* | block_content
* | indentless_block_sequence
* block_node ::= ALIAS
* | properties block_content?
* | block_content
* flow_node ::= ALIAS
* | properties flow_content?
* | flow_content
* properties ::= TAG ANCHOR? | ANCHOR TAG?
* block_content ::= block_collection | flow_collection | SCALAR
* flow_content ::= flow_collection | SCALAR
* block_collection ::= block_sequence | block_mapping
* flow_collection ::= flow_sequence | flow_mapping
* block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
* indentless_sequence ::= (BLOCK-ENTRY block_node?)+
* block_mapping ::= BLOCK-MAPPING_START
* ((KEY block_node_or_indentless_sequence?)?
* (VALUE block_node_or_indentless_sequence?)?)*
* BLOCK-END
* flow_sequence ::= FLOW-SEQUENCE-START
* (flow_sequence_entry FLOW-ENTRY)*
* flow_sequence_entry?
* FLOW-SEQUENCE-END
* flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
* flow_mapping ::= FLOW-MAPPING-START
* (flow_mapping_entry FLOW-ENTRY)*
* flow_mapping_entry?
* FLOW-MAPPING-END
* flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
* FIRST sets:
* stream: { STREAM-START }
* explicit_document: { DIRECTIVE DOCUMENT-START }
* implicit_document: FIRST(block_node)
* block_node: { ALIAS TAG ANCHOR SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START }
* flow_node: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START }
* block_content: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
* flow_content: { FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
* block_collection: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START }
* flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
* block_sequence: { BLOCK-SEQUENCE-START }
* block_mapping: { BLOCK-MAPPING-START }
* block_node_or_indentless_sequence: { ALIAS ANCHOR TAG SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START BLOCK-ENTRY }
* indentless_sequence: { ENTRY }
* flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
* flow_sequence: { FLOW-SEQUENCE-START }
* flow_mapping: { FLOW-MAPPING-START }
* flow_sequence_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
* flow_mapping_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
* </pre>
*
* Since writing a recursive-descendant parser is a straightforward task, we do
* not give many comments here.
*/
public class ParserImpl implements Parser {
private static final Map<String, String> DEFAULT_TAGS = new HashMap<String, String>();
static {
DEFAULT_TAGS.put("!", "!");
DEFAULT_TAGS.put("!!", Tag.PREFIX);
}
protected final Scanner scanner;
private Event currentEvent;
private final ArrayStack<Production> states;
private final ArrayStack<Mark> marks;
private Production state;
private VersionTagsTuple directives;
public ParserImpl(StreamReader reader) {
this(new ScannerImpl(reader));
}
public ParserImpl(Scanner scanner) {
this.scanner = scanner;
currentEvent = null;
directives = new VersionTagsTuple(null, new HashMap<String, String>(DEFAULT_TAGS));
states = new ArrayStack<Production>(100);
marks = new ArrayStack<Mark>(10);
state = new ParseStreamStart();
}
/**
* Check the type of the next event.
*/
public boolean checkEvent(Event.ID choice) {
peekEvent();
return currentEvent != null && currentEvent.is(choice);
}
/**
* Get the next event.
*/
public Event peekEvent() {
if (currentEvent == null) {
if (state != null) {
currentEvent = state.produce();
}
}
return currentEvent;
}
/**
* Get the next event and proceed further.
*/
public Event getEvent() {
peekEvent();
Event value = currentEvent;
currentEvent = null;
return value;
}
/**
* <pre>
* stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
* implicit_document ::= block_node DOCUMENT-END*
* explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
* </pre>
*/
private class ParseStreamStart implements Production {
public Event produce() {
// Parse the stream start.
StreamStartToken token = (StreamStartToken) scanner.getToken();
Event event = new StreamStartEvent(token.getStartMark(), token.getEndMark());
// Prepare the next state.
state = new ParseImplicitDocumentStart();
return event;
}
}
private class ParseImplicitDocumentStart implements Production {
public Event produce() {
// Parse an implicit document.
if (!scanner.checkToken(Token.ID.Directive, Token.ID.DocumentStart, Token.ID.StreamEnd)) {
directives = new VersionTagsTuple(null, DEFAULT_TAGS);
Token token = scanner.peekToken();
Mark startMark = token.getStartMark();
Mark endMark = startMark;
Event event = new DocumentStartEvent(startMark, endMark, false, null, null);
// Prepare the next state.
states.push(new ParseDocumentEnd());
state = new ParseBlockNode();
return event;
} else {
Production p = new ParseDocumentStart();
return p.produce();
}
}
}
private class ParseDocumentStart implements Production {
public Event produce() {
// Parse any extra document end indicators.
while (scanner.checkToken(Token.ID.DocumentEnd)) {
scanner.getToken();
}
// Parse an explicit document.
Event event;
if (!scanner.checkToken(Token.ID.StreamEnd)) {
Token token = scanner.peekToken();
Mark startMark = token.getStartMark();
VersionTagsTuple tuple = processDirectives();
if (!scanner.checkToken(Token.ID.DocumentStart)) {
throw new ParserException(null, null, "expected '<document start>', but found '"
+ scanner.peekToken().getTokenId() + "'", scanner.peekToken().getStartMark());
}
token = scanner.getToken();
Mark endMark = token.getEndMark();
event = new DocumentStartEvent(startMark, endMark, true, tuple.getVersion(),
tuple.getTags());
states.push(new ParseDocumentEnd());
state = new ParseDocumentContent();
} else {
// Parse the end of the stream.
StreamEndToken token = (StreamEndToken) scanner.getToken();
event = new StreamEndEvent(token.getStartMark(), token.getEndMark());
if (!states.isEmpty()) {
throw new YAMLException("Unexpected end of stream. States left: " + states);
}
if (!marks.isEmpty()) {
throw new YAMLException("Unexpected end of stream. Marks left: " + marks);
}
state = null;
}
return event;
}
}
private class ParseDocumentEnd implements Production {
public Event produce() {
// Parse the document end.
Token token = scanner.peekToken();
Mark startMark = token.getStartMark();
Mark endMark = startMark;
boolean explicit = false;
if (scanner.checkToken(Token.ID.DocumentEnd)) {
token = scanner.getToken();
endMark = token.getEndMark();
explicit = true;
}
Event event = new DocumentEndEvent(startMark, endMark, explicit);
// Prepare the next state.
state = new ParseDocumentStart();
return event;
}
}
private class ParseDocumentContent implements Production {
public Event produce() {
Event event;
if (scanner.checkToken(Token.ID.Directive, Token.ID.DocumentStart,
Token.ID.DocumentEnd, Token.ID.StreamEnd)) {
event = processEmptyScalar(scanner.peekToken().getStartMark());
state = states.pop();
return event;
} else {
Production p = new ParseBlockNode();
return p.produce();
}
}
}
@SuppressWarnings("unchecked")
private VersionTagsTuple processDirectives() {
Version yamlVersion = null;
HashMap<String, String> tagHandles = new HashMap<String, String>();
while (scanner.checkToken(Token.ID.Directive)) {
@SuppressWarnings("rawtypes")
DirectiveToken token = (DirectiveToken) scanner.getToken();
if (token.getName().equals("YAML")) {
if (yamlVersion != null) {
throw new ParserException(null, null, "found duplicate YAML directive",
token.getStartMark());
}
List<Integer> value = (List<Integer>) token.getValue();
Integer major = value.get(0);
if (major != 1) {
throw new ParserException(null, null,
"found incompatible YAML document (version 1.* is required)",
token.getStartMark());
}
Integer minor = value.get(1);
switch (minor) {
case 0:
yamlVersion = Version.V1_0;
break;
default:
yamlVersion = Version.V1_1;
break;
}
} else if (token.getName().equals("TAG")) {
List<String> value = (List<String>) token.getValue();
String handle = value.get(0);
String prefix = value.get(1);
if (tagHandles.containsKey(handle)) {
throw new ParserException(null, null, "duplicate tag handle " + handle,
token.getStartMark());
}
tagHandles.put(handle, prefix);
}
}
if (yamlVersion != null || !tagHandles.isEmpty()) {
// directives in the document found - drop the previous
for (String key : DEFAULT_TAGS.keySet()) {
// do not overwrite re-defined tags
if (!tagHandles.containsKey(key)) {
tagHandles.put(key, DEFAULT_TAGS.get(key));
}
}
directives = new VersionTagsTuple(yamlVersion, tagHandles);
}
return directives;
}
/**
* <pre>
* block_node_or_indentless_sequence ::= ALIAS
* | properties (block_content | indentless_block_sequence)?
* | block_content
* | indentless_block_sequence
* block_node ::= ALIAS
* | properties block_content?
* | block_content
* flow_node ::= ALIAS
* | properties flow_content?
* | flow_content
* properties ::= TAG ANCHOR? | ANCHOR TAG?
* block_content ::= block_collection | flow_collection | SCALAR
* flow_content ::= flow_collection | SCALAR
* block_collection ::= block_sequence | block_mapping
* flow_collection ::= flow_sequence | flow_mapping
* </pre>
*/
private class ParseBlockNode implements Production {
public Event produce() {
return parseNode(true, false);
}
}
private Event parseFlowNode() {
return parseNode(false, false);
}
private Event parseBlockNodeOrIndentlessSequence() {
return parseNode(true, true);
}
private Event parseNode(boolean block, boolean indentlessSequence) {
Event event;
Mark startMark = null;
Mark endMark = null;
Mark tagMark = null;
if (scanner.checkToken(Token.ID.Alias)) {
AliasToken token = (AliasToken) scanner.getToken();
event = new AliasEvent(token.getValue(), token.getStartMark(), token.getEndMark());
state = states.pop();
} else {
String anchor = null;
TagTuple tagTokenTag = null;
if (scanner.checkToken(Token.ID.Anchor)) {
AnchorToken token = (AnchorToken) scanner.getToken();
startMark = token.getStartMark();
endMark = token.getEndMark();
anchor = token.getValue();
if (scanner.checkToken(Token.ID.Tag)) {
TagToken tagToken = (TagToken) scanner.getToken();
tagMark = tagToken.getStartMark();
endMark = tagToken.getEndMark();
tagTokenTag = tagToken.getValue();
}
} else if (scanner.checkToken(Token.ID.Tag)) {
TagToken tagToken = (TagToken) scanner.getToken();
startMark = tagToken.getStartMark();
tagMark = startMark;
endMark = tagToken.getEndMark();
tagTokenTag = tagToken.getValue();
if (scanner.checkToken(Token.ID.Anchor)) {
AnchorToken token = (AnchorToken) scanner.getToken();
endMark = token.getEndMark();
anchor = token.getValue();
}
}
String tag = null;
if (tagTokenTag != null) {
String handle = tagTokenTag.getHandle();
String suffix = tagTokenTag.getSuffix();
if (handle != null) {
if (!directives.getTags().containsKey(handle)) {
throw new ParserException("while parsing a node", startMark,
"found undefined tag handle " + handle, tagMark);
}
tag = directives.getTags().get(handle) + suffix;
} else {
tag = suffix;
}
}
if (startMark == null) {
startMark = scanner.peekToken().getStartMark();
endMark = startMark;
}
event = null;
boolean implicit = tag == null || tag.equals("!");
if (indentlessSequence && scanner.checkToken(Token.ID.BlockEntry)) {
endMark = scanner.peekToken().getEndMark();
event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark,
DumperOptions.FlowStyle.BLOCK);
state = new ParseIndentlessSequenceEntry();
} else {
if (scanner.checkToken(Token.ID.Scalar)) {
ScalarToken token = (ScalarToken) scanner.getToken();
endMark = token.getEndMark();
ImplicitTuple implicitValues;
if ((token.getPlain() && tag == null) || "!".equals(tag)) {
implicitValues = new ImplicitTuple(true, false);
} else if (tag == null) {
implicitValues = new ImplicitTuple(false, true);
} else {
implicitValues = new ImplicitTuple(false, false);
}
event = new ScalarEvent(anchor, tag, implicitValues, token.getValue(),
startMark, endMark, token.getStyle());
state = states.pop();
} else if (scanner.checkToken(Token.ID.FlowSequenceStart)) {
endMark = scanner.peekToken().getEndMark();
event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark,
DumperOptions.FlowStyle.FLOW);
state = new ParseFlowSequenceFirstEntry();
} else if (scanner.checkToken(Token.ID.FlowMappingStart)) {
endMark = scanner.peekToken().getEndMark();
event = new MappingStartEvent(anchor, tag, implicit, startMark, endMark,
DumperOptions.FlowStyle.FLOW);
state = new ParseFlowMappingFirstKey();
} else if (block && scanner.checkToken(Token.ID.BlockSequenceStart)) {
endMark = scanner.peekToken().getStartMark();
event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark,
DumperOptions.FlowStyle.BLOCK);
state = new ParseBlockSequenceFirstEntry();
} else if (block && scanner.checkToken(Token.ID.BlockMappingStart)) {
endMark = scanner.peekToken().getStartMark();
event = new MappingStartEvent(anchor, tag, implicit, startMark, endMark,
DumperOptions.FlowStyle.BLOCK);
state = new ParseBlockMappingFirstKey();
} else if (anchor != null || tag != null) {
// Empty scalars are allowed even if a tag or an anchor is
// specified.
event = new ScalarEvent(anchor, tag, new ImplicitTuple(implicit, false), "",
startMark, endMark, DumperOptions.ScalarStyle.PLAIN);
state = states.pop();
} else {
String node;
if (block) {
node = "block";
} else {
node = "flow";
}
Token token = scanner.peekToken();
throw new ParserException("while parsing a " + node + " node", startMark,
"expected the node content, but found '" + token.getTokenId() + "'",
token.getStartMark());
}
}
}
return event;
}
// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)*
// BLOCK-END
private class ParseBlockSequenceFirstEntry implements Production {
public Event produce() {
Token token = scanner.getToken();
marks.push(token.getStartMark());
return new ParseBlockSequenceEntry().produce();
}
}
private class ParseBlockSequenceEntry implements Production {
public Event produce() {
if (scanner.checkToken(Token.ID.BlockEntry)) {
BlockEntryToken token = (BlockEntryToken) scanner.getToken();
if (!scanner.checkToken(Token.ID.BlockEntry, Token.ID.BlockEnd)) {
states.push(new ParseBlockSequenceEntry());
return new ParseBlockNode().produce();
} else {
state = new ParseBlockSequenceEntry();
return processEmptyScalar(token.getEndMark());
}
}
if (!scanner.checkToken(Token.ID.BlockEnd)) {
Token token = scanner.peekToken();
throw new ParserException("while parsing a block collection", marks.pop(),
"expected <block end>, but found '" + token.getTokenId() + "'",
token.getStartMark());
}
Token token = scanner.getToken();
Event event = new SequenceEndEvent(token.getStartMark(), token.getEndMark());
state = states.pop();
marks.pop();
return event;
}
}
// indentless_sequence ::= (BLOCK-ENTRY block_node?)+
private class ParseIndentlessSequenceEntry implements Production {
public Event produce() {
if (scanner.checkToken(Token.ID.BlockEntry)) {
Token token = scanner.getToken();
if (!scanner.checkToken(Token.ID.BlockEntry, Token.ID.Key, Token.ID.Value,
Token.ID.BlockEnd)) {
states.push(new ParseIndentlessSequenceEntry());
return new ParseBlockNode().produce();
} else {
state = new ParseIndentlessSequenceEntry();
return processEmptyScalar(token.getEndMark());
}
}
Token token = scanner.peekToken();
Event event = new SequenceEndEvent(token.getStartMark(), token.getEndMark());
state = states.pop();
return event;
}
}
private class ParseBlockMappingFirstKey implements Production {
public Event produce() {
Token token = scanner.getToken();
marks.push(token.getStartMark());
return new ParseBlockMappingKey().produce();
}
}
private class ParseBlockMappingKey implements Production {
public Event produce() {
if (scanner.checkToken(Token.ID.Key)) {
Token token = scanner.getToken();
if (!scanner.checkToken(Token.ID.Key, Token.ID.Value, Token.ID.BlockEnd)) {
states.push(new ParseBlockMappingValue());
return parseBlockNodeOrIndentlessSequence();
} else {
state = new ParseBlockMappingValue();
return processEmptyScalar(token.getEndMark());
}
}
if (!scanner.checkToken(Token.ID.BlockEnd)) {
Token token = scanner.peekToken();
throw new ParserException("while parsing a block mapping", marks.pop(),
"expected <block end>, but found '" + token.getTokenId() + "'",
token.getStartMark());
}
Token token = scanner.getToken();
Event event = new MappingEndEvent(token.getStartMark(), token.getEndMark());
state = states.pop();
marks.pop();
return event;
}
}
private class ParseBlockMappingValue implements Production {
public Event produce() {
if (scanner.checkToken(Token.ID.Value)) {
Token token = scanner.getToken();
if (!scanner.checkToken(Token.ID.Key, Token.ID.Value, Token.ID.BlockEnd)) {
states.push(new ParseBlockMappingKey());
return parseBlockNodeOrIndentlessSequence();
} else {
state = new ParseBlockMappingKey();
return processEmptyScalar(token.getEndMark());
}
}
state = new ParseBlockMappingKey();
Token token = scanner.peekToken();
return processEmptyScalar(token.getStartMark());
}
}
/**
* <pre>
* flow_sequence ::= FLOW-SEQUENCE-START
* (flow_sequence_entry FLOW-ENTRY)*
* flow_sequence_entry?
* FLOW-SEQUENCE-END
* flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
* Note that while production rules for both flow_sequence_entry and
* flow_mapping_entry are equal, their interpretations are different.
* For `flow_sequence_entry`, the part `KEY flow_node? (VALUE flow_node?)?`
* generate an inline mapping (set syntax).
* </pre>
*/
private class ParseFlowSequenceFirstEntry implements Production {
public Event produce() {
Token token = scanner.getToken();
marks.push(token.getStartMark());
return new ParseFlowSequenceEntry(true).produce();
}
}
private class ParseFlowSequenceEntry implements Production {
private boolean first = false;
public ParseFlowSequenceEntry(boolean first) {
this.first = first;
}
public Event produce() {
if (!scanner.checkToken(Token.ID.FlowSequenceEnd)) {
if (!first) {
if (scanner.checkToken(Token.ID.FlowEntry)) {
scanner.getToken();
} else {
Token token = scanner.peekToken();
throw new ParserException("while parsing a flow sequence", marks.pop(),
"expected ',' or ']', but got " + token.getTokenId(),
token.getStartMark());
}
}
if (scanner.checkToken(Token.ID.Key)) {
Token token = scanner.peekToken();
Event event = new MappingStartEvent(null, null, true, token.getStartMark(),
token.getEndMark(), DumperOptions.FlowStyle.FLOW);
state = new ParseFlowSequenceEntryMappingKey();
return event;
} else if (!scanner.checkToken(Token.ID.FlowSequenceEnd)) {
states.push(new ParseFlowSequenceEntry(false));
return parseFlowNode();
}
}
Token token = scanner.getToken();
Event event = new SequenceEndEvent(token.getStartMark(), token.getEndMark());
state = states.pop();
marks.pop();
return event;
}
}
private class ParseFlowSequenceEntryMappingKey implements Production {
public Event produce() {
Token token = scanner.getToken();
if (!scanner.checkToken(Token.ID.Value, Token.ID.FlowEntry, Token.ID.FlowSequenceEnd)) {
states.push(new ParseFlowSequenceEntryMappingValue());
return parseFlowNode();
} else {
state = new ParseFlowSequenceEntryMappingValue();
return processEmptyScalar(token.getEndMark());
}
}
}
private class ParseFlowSequenceEntryMappingValue implements Production {
public Event produce() {
if (scanner.checkToken(Token.ID.Value)) {
Token token = scanner.getToken();
if (!scanner.checkToken(Token.ID.FlowEntry, Token.ID.FlowSequenceEnd)) {
states.push(new ParseFlowSequenceEntryMappingEnd());
return parseFlowNode();
} else {
state = new ParseFlowSequenceEntryMappingEnd();
return processEmptyScalar(token.getEndMark());
}
} else {
state = new ParseFlowSequenceEntryMappingEnd();
Token token = scanner.peekToken();
return processEmptyScalar(token.getStartMark());
}
}
}
private class ParseFlowSequenceEntryMappingEnd implements Production {
public Event produce() {
state = new ParseFlowSequenceEntry(false);
Token token = scanner.peekToken();
return new MappingEndEvent(token.getStartMark(), token.getEndMark());
}
}
/**
* <pre>
* flow_mapping ::= FLOW-MAPPING-START
* (flow_mapping_entry FLOW-ENTRY)*
* flow_mapping_entry?
* FLOW-MAPPING-END
* flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
* </pre>
*/
private class ParseFlowMappingFirstKey implements Production {
public Event produce() {
Token token = scanner.getToken();
marks.push(token.getStartMark());
return new ParseFlowMappingKey(true).produce();
}
}
private class ParseFlowMappingKey implements Production {
private boolean first = false;
public ParseFlowMappingKey(boolean first) {
this.first = first;
}
public Event produce() {
if (!scanner.checkToken(Token.ID.FlowMappingEnd)) {
if (!first) {
if (scanner.checkToken(Token.ID.FlowEntry)) {
scanner.getToken();
} else {
Token token = scanner.peekToken();
throw new ParserException("while parsing a flow mapping", marks.pop(),
"expected ',' or '}', but got " + token.getTokenId(),
token.getStartMark());
}
}
if (scanner.checkToken(Token.ID.Key)) {
Token token = scanner.getToken();
if (!scanner.checkToken(Token.ID.Value, Token.ID.FlowEntry,
Token.ID.FlowMappingEnd)) {
states.push(new ParseFlowMappingValue());
return parseFlowNode();
} else {
state = new ParseFlowMappingValue();
return processEmptyScalar(token.getEndMark());
}
} else if (!scanner.checkToken(Token.ID.FlowMappingEnd)) {
states.push(new ParseFlowMappingEmptyValue());
return parseFlowNode();
}
}
Token token = scanner.getToken();
Event event = new MappingEndEvent(token.getStartMark(), token.getEndMark());
state = states.pop();
marks.pop();
return event;
}
}
private class ParseFlowMappingValue implements Production {
public Event produce() {
if (scanner.checkToken(Token.ID.Value)) {
Token token = scanner.getToken();
if (!scanner.checkToken(Token.ID.FlowEntry, Token.ID.FlowMappingEnd)) {
states.push(new ParseFlowMappingKey(false));
return parseFlowNode();
} else {
state = new ParseFlowMappingKey(false);
return processEmptyScalar(token.getEndMark());
}
} else {
state = new ParseFlowMappingKey(false);
Token token = scanner.peekToken();
return processEmptyScalar(token.getStartMark());
}
}
}
private class ParseFlowMappingEmptyValue implements Production {
public Event produce() {
state = new ParseFlowMappingKey(false);
return processEmptyScalar(scanner.peekToken().getStartMark());
}
}
/**
* <pre>
* block_mapping ::= BLOCK-MAPPING_START
* ((KEY block_node_or_indentless_sequence?)?
* (VALUE block_node_or_indentless_sequence?)?)*
* BLOCK-END
* </pre>
*/
private Event processEmptyScalar(Mark mark) {
return new ScalarEvent(null, null, new ImplicitTuple(true, false), "", mark, mark, DumperOptions.ScalarStyle.PLAIN);
}
}

View File

@ -0,0 +1,28 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.parser;
import io.jenkins.plugins.casc.snakeyaml.events.Event;
/**
* Helper for {@link ParserImpl}. A grammar rule to apply given the symbols on
* top of its stack and the next input token
*
* @see <a href="http://en.wikipedia.org/wiki/LL_parser"></a>
*/
interface Production {
Event produce();
}

View File

@ -0,0 +1,46 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.parser;
import java.util.Map;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions.Version;
/**
* Store the internal state for directives
*/
class VersionTagsTuple {
private Version version;
private Map<String, String> tags;
public VersionTagsTuple(Version version, Map<String, String> tags) {
this.version = version;
this.tags = tags;
}
public Version getVersion() {
return version;
}
public Map<String, String> getTags() {
return tags;
}
@Override
public String toString() {
return String.format("VersionTagsTuple<%s, %s>", version, tags);
}
}

View File

@ -0,0 +1,52 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.reader;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
public class ReaderException extends YAMLException {
private static final long serialVersionUID = 8710781187529689083L;
private final String name;
private final int codePoint;
private final int position;
public ReaderException(String name, int position, int codePoint, String message) {
super(message);
this.name = name;
this.codePoint = codePoint;
this.position = position;
}
public String getName() {
return name;
}
public int getCodePoint() {
return codePoint;
}
public int getPosition() {
return position;
}
@Override
public String toString() {
final String s = new String(Character.toChars(codePoint));
return "unacceptable code point '" + s + "' (0x"
+ Integer.toHexString(codePoint).toUpperCase() + ") " + getMessage()
+ "\nin \"" + name + "\", position " + position;
}
}

View File

@ -0,0 +1,237 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.reader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.Arrays;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
import io.jenkins.plugins.casc.snakeyaml.scanner.Constant;
/**
* Reader: checks if code points are in allowed range. Returns '\0' when end of
* data has been reached.
*/
public class StreamReader {
private String name;
private final Reader stream;
/**
* Read data (as a moving window for input stream)
*/
private int[] dataWindow;
/**
* Real length of the data in dataWindow
*/
private int dataLength;
/**
* The variable points to the current position in the data array
*/
private int pointer = 0;
private boolean eof;
/**
* index is only required to implement 1024 key length restriction
* http://yaml.org/spec/1.1/#simple key/
* It must count code points, but it counts characters (to be fixed)
*/
private int index = 0; // in code points
private int line = 0;
private int column = 0; //in code points
private char[] buffer; // temp buffer for one read operation (to avoid
// creating the array in stack)
private static final int BUFFER_SIZE = 1025;
public StreamReader(String stream) {
this(new StringReader(stream));
this.name = "'string'";
}
public StreamReader(Reader reader) {
this.name = "'reader'";
this.dataWindow = new int[0];
this.dataLength = 0;
this.stream = reader;
this.eof = false;
this.buffer = new char[BUFFER_SIZE];
}
public static boolean isPrintable(final String data) {
final int length = data.length();
for (int offset = 0; offset < length; ) {
final int codePoint = data.codePointAt(offset);
if (!isPrintable(codePoint)) {
return false;
}
offset += Character.charCount(codePoint);
}
return true;
}
public static boolean isPrintable(final int c) {
return (c >= 0x20 && c <= 0x7E) || c == 0x9 || c == 0xA || c == 0xD || c == 0x85
|| (c >= 0xA0 && c <= 0xD7FF) || (c >= 0xE000 && c <= 0xFFFD)
|| (c >= 0x10000 && c <= 0x10FFFF);
}
public Mark getMark() {
return new Mark(name, this.index, this.line, this.column, this.dataWindow, this.pointer);
}
public void forward() {
forward(1);
}
/**
* read the next length characters and move the pointer.
* if the last character is high surrogate one more character will be read
*
* @param length amount of characters to move forward
*/
public void forward(int length) {
for (int i = 0; i < length && ensureEnoughData(); i++) {
int c = dataWindow[pointer++];
this.index++;
if (Constant.LINEBR.has(c)
|| (c == '\r' && (ensureEnoughData() && dataWindow[pointer] != '\n'))) {
this.line++;
this.column = 0;
} else if (c != 0xFEFF) {
this.column++;
}
}
}
public int peek() {
return (ensureEnoughData()) ? dataWindow[pointer] : '\0';
}
/**
* Peek the next index-th code point
*
* @param index to peek
* @return the next index-th code point
*/
public int peek(int index) {
return (ensureEnoughData(index)) ? dataWindow[pointer + index] : '\0';
}
/**
* peek the next length code points
*
* @param length amount of the characters to peek
* @return the next length code points
*/
public String prefix(int length) {
if (length == 0) {
return "";
} else if (ensureEnoughData(length)) {
return new String(this.dataWindow, pointer, length);
} else {
return new String(this.dataWindow, pointer,
Math.min(length, dataLength - pointer));
}
}
/**
* prefix(length) immediately followed by forward(length)
* @param length amount of characters to get
* @return the next length code points
*/
public String prefixForward(int length) {
final String prefix = prefix(length);
this.pointer += length;
this.index += length;
// prefix never contains new line characters
this.column += length;
return prefix;
}
private boolean ensureEnoughData() {
return ensureEnoughData(0);
}
private boolean ensureEnoughData(int size) {
if (!eof && pointer + size >= dataLength) {
update();
}
return (this.pointer + size) < dataLength;
}
private void update() {
try {
int read = stream.read(buffer, 0, BUFFER_SIZE - 1);
if (read > 0) {
int cpIndex = (dataLength - pointer);
dataWindow = Arrays.copyOfRange(dataWindow, pointer, dataLength + read);
if (Character.isHighSurrogate(buffer[read - 1])) {
if (stream.read(buffer, read, 1) == -1) {
eof = true;
} else {
read++;
}
}
int nonPrintable = ' ';
for (int i = 0; i < read; cpIndex++) {
int codePoint = Character.codePointAt(buffer, i);
dataWindow[cpIndex] = codePoint;
if (isPrintable(codePoint)) {
i += Character.charCount(codePoint);
} else {
nonPrintable = codePoint;
i = read;
}
}
dataLength = cpIndex;
pointer = 0;
if (nonPrintable != ' ') {
throw new ReaderException(name, cpIndex - 1, nonPrintable,
"special characters are not allowed");
}
} else {
eof = true;
}
} catch (IOException ioe) {
throw new YAMLException(ioe);
}
}
public int getColumn() {
return column;
}
/**
* @return current position as number (in characters) from the beginning of the stream
*/
public int getIndex() {
return index;
}
public int getLine() {
return line;
}
}

View File

@ -0,0 +1,127 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.reader;
/**
version: 1.1 / 2007-01-25
- changed BOM recognition ordering (longer boms first)
Original pseudocode : Thomas Weidenfeller
Implementation tweaked: Aki Nieminen
Implementation changed: Andrey Somov
* UTF-32 removed because it is not supported by YAML
* no default encoding
http://www.unicode.org/unicode/faq/utf_bom.html
BOMs:
00 00 FE FF = UTF-32, big-endian
FF FE 00 00 = UTF-32, little-endian
EF BB BF = UTF-8,
FE FF = UTF-16, big-endian
FF FE = UTF-16, little-endian
Win2k Notepad:
Unicode format = UTF-16LE
***/
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PushbackInputStream;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
/**
* Generic unicode textreader, which will use BOM mark to identify the encoding
* to be used. If BOM is not found then use a given default or system encoding.
*/
public class UnicodeReader extends Reader {
private static final Charset UTF8 = Charset.forName("UTF-8");
private static final Charset UTF16BE = Charset.forName("UTF-16BE");
private static final Charset UTF16LE = Charset.forName("UTF-16LE");
PushbackInputStream internalIn;
InputStreamReader internalIn2 = null;
private static final int BOM_SIZE = 3;
/**
* @param in
* InputStream to be read
*/
public UnicodeReader(InputStream in) {
internalIn = new PushbackInputStream(in, BOM_SIZE);
}
/**
* Get stream encoding or NULL if stream is uninitialized. Call init() or
* read() method to initialize it.
* @return the name of the character encoding being used by this stream.
*/
public String getEncoding() {
return internalIn2.getEncoding();
}
/**
* Read-ahead four bytes and check for BOM marks. Extra bytes are unread
* back to the stream, only BOM bytes are skipped.
* @throws IOException if InputStream cannot be created
*/
protected void init() throws IOException {
if (internalIn2 != null)
return;
Charset encoding;
byte bom[] = new byte[BOM_SIZE];
int n, unread;
n = internalIn.read(bom, 0, bom.length);
if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF)) {
encoding = UTF8;
unread = n - 3;
} else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) {
encoding = UTF16BE;
unread = n - 2;
} else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) {
encoding = UTF16LE;
unread = n - 2;
} else {
// Unicode BOM mark not found, unread all bytes
encoding = UTF8;
unread = n;
}
if (unread > 0)
internalIn.unread(bom, (n - unread), unread);
// Use given encoding
CharsetDecoder decoder = encoding.newDecoder().onUnmappableCharacter(
CodingErrorAction.REPORT);
internalIn2 = new InputStreamReader(internalIn, decoder);
}
public void close() throws IOException {
init();
internalIn2.close();
}
public int read(char[] cbuf, int off, int len) throws IOException {
init();
return internalIn2.read(cbuf, off, len);
}
}

View File

@ -0,0 +1,210 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.representer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions.FlowStyle;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions.ScalarStyle;
import io.jenkins.plugins.casc.snakeyaml.introspector.PropertyUtils;
import io.jenkins.plugins.casc.snakeyaml.nodes.AnchorNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.MappingNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.Node;
import io.jenkins.plugins.casc.snakeyaml.nodes.NodeTuple;
import io.jenkins.plugins.casc.snakeyaml.nodes.ScalarNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.SequenceNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.Tag;
/**
* Represent basic YAML structures: scalar, sequence, mapping
*/
public abstract class BaseRepresenter {
protected final Map<Class<?>, Represent> representers = new HashMap<Class<?>, Represent>();
/**
* in Java 'null' is not a type. So we have to keep the null representer
* separately otherwise it will coincide with the default representer which
* is stored with the key null.
*/
protected Represent nullRepresenter;
// the order is important (map can be also a sequence of key-values)
protected final Map<Class<?>, Represent> multiRepresenters = new LinkedHashMap<Class<?>, Represent>();
protected DumperOptions.ScalarStyle defaultScalarStyle = null; //not explicitly defined
protected FlowStyle defaultFlowStyle = FlowStyle.AUTO;
protected final Map<Object, Node> representedObjects = new IdentityHashMap<Object, Node>() {
private static final long serialVersionUID = -5576159264232131854L;
public Node put(Object key, Node value) {
return super.put(key, new AnchorNode(value));
}
};
protected Object objectToRepresent;
private PropertyUtils propertyUtils;
private boolean explicitPropertyUtils = false;
public Node represent(Object data) {
Node node = representData(data);
representedObjects.clear();
objectToRepresent = null;
return node;
}
protected final Node representData(Object data) {
objectToRepresent = data;
// check for identity
if (representedObjects.containsKey(objectToRepresent)) {
Node node = representedObjects.get(objectToRepresent);
return node;
}
// }
// check for null first
if (data == null) {
Node node = nullRepresenter.representData(null);
return node;
}
// check the same class
Node node;
Class<?> clazz = data.getClass();
if (representers.containsKey(clazz)) {
Represent representer = representers.get(clazz);
node = representer.representData(data);
} else {
// check the parents
for (Class<?> repr : multiRepresenters.keySet()) {
if (repr != null && repr.isInstance(data)) {
Represent representer = multiRepresenters.get(repr);
node = representer.representData(data);
return node;
}
}
// check defaults
if (multiRepresenters.containsKey(null)) {
Represent representer = multiRepresenters.get(null);
node = representer.representData(data);
} else {
Represent representer = representers.get(null);
node = representer.representData(data);
}
}
return node;
}
protected Node representScalar(Tag tag, String value, DumperOptions.ScalarStyle style) {
if (style == null) {
style = this.defaultScalarStyle;
}
Node node = new ScalarNode(tag, value, null, null, style);
return node;
}
protected Node representScalar(Tag tag, String value) {
return representScalar(tag, value, null);
}
protected Node representSequence(Tag tag, Iterable<?> sequence, DumperOptions.FlowStyle flowStyle) {
int size = 10;// default for ArrayList
if (sequence instanceof List<?>) {
size = ((List<?>) sequence).size();
}
List<Node> value = new ArrayList<Node>(size);
SequenceNode node = new SequenceNode(tag, value, flowStyle);
representedObjects.put(objectToRepresent, node);
DumperOptions.FlowStyle bestStyle = FlowStyle.FLOW;
for (Object item : sequence) {
Node nodeItem = representData(item);
if (!(nodeItem instanceof ScalarNode && ((ScalarNode) nodeItem).isPlain())) {
bestStyle = FlowStyle.BLOCK;
}
value.add(nodeItem);
}
if (flowStyle == FlowStyle.AUTO) {
if (defaultFlowStyle != FlowStyle.AUTO) {
node.setFlowStyle(defaultFlowStyle);
} else {
node.setFlowStyle(bestStyle);
}
}
return node;
}
protected Node representMapping(Tag tag, Map<?, ?> mapping, DumperOptions.FlowStyle flowStyle) {
List<NodeTuple> value = new ArrayList<NodeTuple>(mapping.size());
MappingNode node = new MappingNode(tag, value, flowStyle);
representedObjects.put(objectToRepresent, node);
DumperOptions.FlowStyle bestStyle = FlowStyle.FLOW;
for (Map.Entry<?, ?> entry : mapping.entrySet()) {
Node nodeKey = representData(entry.getKey());
Node nodeValue = representData(entry.getValue());
if (!(nodeKey instanceof ScalarNode && ((ScalarNode) nodeKey).isPlain())) {
bestStyle = FlowStyle.BLOCK;
}
if (!(nodeValue instanceof ScalarNode && ((ScalarNode) nodeValue).isPlain())) {
bestStyle = FlowStyle.BLOCK;
}
value.add(new NodeTuple(nodeKey, nodeValue));
}
if (flowStyle == FlowStyle.AUTO) {
if (defaultFlowStyle != FlowStyle.AUTO) {
node.setFlowStyle(defaultFlowStyle);
} else {
node.setFlowStyle(bestStyle);
}
}
return node;
}
public void setDefaultScalarStyle(ScalarStyle defaultStyle) {
this.defaultScalarStyle = defaultStyle;
}
public ScalarStyle getDefaultScalarStyle() {
if (defaultScalarStyle == null) {
return ScalarStyle.PLAIN;
}
return defaultScalarStyle;
}
public void setDefaultFlowStyle(FlowStyle defaultFlowStyle) {
this.defaultFlowStyle = defaultFlowStyle;
}
public FlowStyle getDefaultFlowStyle() {
return this.defaultFlowStyle;
}
public void setPropertyUtils(PropertyUtils propertyUtils) {
this.propertyUtils = propertyUtils;
this.explicitPropertyUtils = true;
}
public final PropertyUtils getPropertyUtils() {
if (propertyUtils == null) {
propertyUtils = new PropertyUtils();
}
return propertyUtils;
}
public final boolean isExplicitPropertyUtils() {
return explicitPropertyUtils;
}
}

View File

@ -0,0 +1,36 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.representer;
import io.jenkins.plugins.casc.snakeyaml.nodes.Node;
/**
* Create a Node Graph out of the provided Native Data Structure (Java
* instance).
*
* @see <a href="http://yaml.org/spec/1.1/#id859109">Chapter 3. Processing YAML
* Information</a>
*/
public interface Represent {
/**
* Create a Node
*
* @param data
* the instance to represent
* @return Node to dump
*/
Node representData(Object data);
}

View File

@ -0,0 +1,275 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.representer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions.FlowStyle;
import io.jenkins.plugins.casc.snakeyaml.TypeDescription;
import io.jenkins.plugins.casc.snakeyaml.introspector.Property;
import io.jenkins.plugins.casc.snakeyaml.introspector.PropertyUtils;
import io.jenkins.plugins.casc.snakeyaml.nodes.MappingNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.Node;
import io.jenkins.plugins.casc.snakeyaml.nodes.NodeId;
import io.jenkins.plugins.casc.snakeyaml.nodes.NodeTuple;
import io.jenkins.plugins.casc.snakeyaml.nodes.ScalarNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.SequenceNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.Tag;
/**
* Represent JavaBeans
*/
public class Representer extends SafeRepresenter {
protected Map<Class<? extends Object>, TypeDescription> typeDefinitions = Collections
.emptyMap();
public Representer() {
this.representers.put(null, new RepresentJavaBean());
}
public TypeDescription addTypeDescription(TypeDescription td) {
if (Collections.EMPTY_MAP == typeDefinitions) {
typeDefinitions = new HashMap<Class<? extends Object>, TypeDescription>();
}
if (td.getTag() != null) {
addClassTag(td.getType(), td.getTag());
}
td.setPropertyUtils(getPropertyUtils());
return typeDefinitions.put(td.getType(), td);
}
@Override
public void setPropertyUtils(PropertyUtils propertyUtils) {
super.setPropertyUtils(propertyUtils);
Collection<TypeDescription> tds = typeDefinitions.values();
for (TypeDescription typeDescription : tds) {
typeDescription.setPropertyUtils(propertyUtils);
}
}
protected class RepresentJavaBean implements Represent {
public Node representData(Object data) {
return representJavaBean(getProperties(data.getClass()), data);
}
}
/**
* Tag logic:
* - explicit root tag is set in serializer
* - if there is a predefined class tag it is used
* - a global tag with class name is always used as tag. The JavaBean parent
* of the specified JavaBean may set another tag (tag:yaml.org,2002:map)
* when the property class is the same as runtime class
*
* @param properties
* JavaBean getters
* @param javaBean
* instance for Node
* @return Node to get serialized
*/
protected MappingNode representJavaBean(Set<Property> properties, Object javaBean) {
List<NodeTuple> value = new ArrayList<NodeTuple>(properties.size());
Tag tag;
Tag customTag = classTags.get(javaBean.getClass());
tag = customTag != null ? customTag : new Tag(javaBean.getClass());
// flow style will be chosen by BaseRepresenter
MappingNode node = new MappingNode(tag, value, FlowStyle.AUTO);
representedObjects.put(javaBean, node);
DumperOptions.FlowStyle bestStyle = FlowStyle.FLOW;
for (Property property : properties) {
Object memberValue = property.get(javaBean);
Tag customPropertyTag = memberValue == null ? null
: classTags.get(memberValue.getClass());
NodeTuple tuple = representJavaBeanProperty(javaBean, property, memberValue,
customPropertyTag);
if (tuple == null) {
continue;
}
if (!((ScalarNode) tuple.getKeyNode()).isPlain()) {
bestStyle = FlowStyle.BLOCK;
}
Node nodeValue = tuple.getValueNode();
if (!(nodeValue instanceof ScalarNode && ((ScalarNode) nodeValue).isPlain())) {
bestStyle = FlowStyle.BLOCK;
}
value.add(tuple);
}
if (defaultFlowStyle != FlowStyle.AUTO) {
node.setFlowStyle(defaultFlowStyle);
} else {
node.setFlowStyle(bestStyle);
}
return node;
}
/**
* Represent one JavaBean property.
*
* @param javaBean
* - the instance to be represented
* @param property
* - the property of the instance
* @param propertyValue
* - value to be represented
* @param customTag
* - user defined Tag
* @return NodeTuple to be used in a MappingNode. Return null to skip the
* property
*/
protected NodeTuple representJavaBeanProperty(Object javaBean, Property property,
Object propertyValue, Tag customTag) {
ScalarNode nodeKey = (ScalarNode) representData(property.getName());
// the first occurrence of the node must keep the tag
boolean hasAlias = this.representedObjects.containsKey(propertyValue);
Node nodeValue = representData(propertyValue);
if (propertyValue != null && !hasAlias) {
NodeId nodeId = nodeValue.getNodeId();
if (customTag == null) {
if (nodeId == NodeId.scalar) {
//generic Enum requires the full tag
if (property.getType() != java.lang.Enum.class) {
if (propertyValue instanceof Enum<?>) {
nodeValue.setTag(Tag.STR);
}
}
} else {
if (nodeId == NodeId.mapping) {
if (property.getType() == propertyValue.getClass()) {
if (!(propertyValue instanceof Map<?, ?>)) {
if (!nodeValue.getTag().equals(Tag.SET)) {
nodeValue.setTag(Tag.MAP);
}
}
}
}
checkGlobalTag(property, nodeValue, propertyValue);
}
}
}
return new NodeTuple(nodeKey, nodeValue);
}
/**
* Remove redundant global tag for a type safe (generic) collection if it is
* the same as defined by the JavaBean property
*
* @param property
* - JavaBean property
* @param node
* - representation of the property
* @param object
* - instance represented by the node
*/
@SuppressWarnings("unchecked")
protected void checkGlobalTag(Property property, Node node, Object object) {
// Skip primitive arrays.
if (object.getClass().isArray() && object.getClass().getComponentType().isPrimitive()) {
return;
}
Class<?>[] arguments = property.getActualTypeArguments();
if (arguments != null) {
if (node.getNodeId() == NodeId.sequence) {
// apply map tag where class is the same
Class<? extends Object> t = arguments[0];
SequenceNode snode = (SequenceNode) node;
Iterable<Object> memberList = Collections.EMPTY_LIST;
if (object.getClass().isArray()) {
memberList = Arrays.asList((Object[]) object);
} else if (object instanceof Iterable<?>) {
// list
memberList = (Iterable<Object>) object;
}
Iterator<Object> iter = memberList.iterator();
if (iter.hasNext()) {
for (Node childNode : snode.getValue()) {
Object member = iter.next();
if (member != null) {
if (t.equals(member.getClass()))
if (childNode.getNodeId() == NodeId.mapping) {
childNode.setTag(Tag.MAP);
}
}
}
}
} else if (object instanceof Set) {
Class<?> t = arguments[0];
MappingNode mnode = (MappingNode) node;
Iterator<NodeTuple> iter = mnode.getValue().iterator();
Set<?> set = (Set<?>) object;
for (Object member : set) {
NodeTuple tuple = iter.next();
Node keyNode = tuple.getKeyNode();
if (t.equals(member.getClass())) {
if (keyNode.getNodeId() == NodeId.mapping) {
keyNode.setTag(Tag.MAP);
}
}
}
} else if (object instanceof Map) { // NodeId.mapping ends-up here
Class<?> keyType = arguments[0];
Class<?> valueType = arguments[1];
MappingNode mnode = (MappingNode) node;
for (NodeTuple tuple : mnode.getValue()) {
resetTag(keyType, tuple.getKeyNode());
resetTag(valueType, tuple.getValueNode());
}
} else {
// the type for collection entries cannot be
// detected
}
}
}
private void resetTag(Class<? extends Object> type, Node node) {
Tag tag = node.getTag();
if (tag.matches(type)) {
if (Enum.class.isAssignableFrom(type)) {
node.setTag(Tag.STR);
} else {
node.setTag(Tag.MAP);
}
}
}
/**
* Get JavaBean properties to be serialised. The order is respected. This
* method may be overridden to provide custom property selection or order.
*
* @param type
* - JavaBean to inspect the properties
* @return properties to serialise
*/
protected Set<Property> getProperties(Class<? extends Object> type) {
if (typeDefinitions.containsKey(type)) {
return typeDefinitions.get(type).getProperties();
}
return getPropertyUtils().getProperties(type);
}
}

View File

@ -0,0 +1,451 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.representer;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;
import java.util.regex.Pattern;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
import io.jenkins.plugins.casc.snakeyaml.external.biz.base64Coder.Base64Coder;
import io.jenkins.plugins.casc.snakeyaml.nodes.Node;
import io.jenkins.plugins.casc.snakeyaml.nodes.Tag;
import io.jenkins.plugins.casc.snakeyaml.reader.StreamReader;
/**
* Represent standard Java classes
*/
class SafeRepresenter extends BaseRepresenter {
protected Map<Class<? extends Object>, Tag> classTags;
protected TimeZone timeZone = null;
public SafeRepresenter() {
this.nullRepresenter = new RepresentNull();
this.representers.put(String.class, new RepresentString());
this.representers.put(Boolean.class, new RepresentBoolean());
this.representers.put(Character.class, new RepresentString());
this.representers.put(UUID.class, new RepresentUuid());
this.representers.put(byte[].class, new RepresentByteArray());
Represent primitiveArray = new RepresentPrimitiveArray();
representers.put(short[].class, primitiveArray);
representers.put(int[].class, primitiveArray);
representers.put(long[].class, primitiveArray);
representers.put(float[].class, primitiveArray);
representers.put(double[].class, primitiveArray);
representers.put(char[].class, primitiveArray);
representers.put(boolean[].class, primitiveArray);
this.multiRepresenters.put(Number.class, new RepresentNumber());
this.multiRepresenters.put(List.class, new RepresentList());
this.multiRepresenters.put(Map.class, new RepresentMap());
this.multiRepresenters.put(Set.class, new RepresentSet());
this.multiRepresenters.put(Iterator.class, new RepresentIterator());
this.multiRepresenters.put(new Object[0].getClass(), new RepresentArray());
this.multiRepresenters.put(Date.class, new RepresentDate());
this.multiRepresenters.put(Enum.class, new RepresentEnum());
this.multiRepresenters.put(Calendar.class, new RepresentDate());
classTags = new HashMap<Class<? extends Object>, Tag>();
}
protected Tag getTag(Class<?> clazz, Tag defaultTag) {
if (classTags.containsKey(clazz)) {
return classTags.get(clazz);
} else {
return defaultTag;
}
}
/**
* Define a tag for the <code>Class</code> to serialize.
*
* @param clazz
* <code>Class</code> which tag is changed
* @param tag
* new tag to be used for every instance of the specified
* <code>Class</code>
* @return the previous tag associated with the <code>Class</code>
*/
public Tag addClassTag(Class<? extends Object> clazz, Tag tag) {
if (tag == null) {
throw new NullPointerException("Tag must be provided.");
}
return classTags.put(clazz, tag);
}
protected class RepresentNull implements Represent {
public Node representData(Object data) {
return representScalar(Tag.NULL, "null");
}
}
public static Pattern MULTILINE_PATTERN = Pattern.compile("\n|\u0085|\u2028|\u2029");
protected class RepresentString implements Represent {
public Node representData(Object data) {
Tag tag = Tag.STR;
DumperOptions.ScalarStyle style = null;//not defined
String value = data.toString();
if (!StreamReader.isPrintable(value)) {
tag = Tag.BINARY;
char[] binary;
try {
final byte[] bytes = value.getBytes("UTF-8");
// sometimes above will just silently fail - it will return incomplete data
// it happens when String has invalid code points
// (for example half surrogate character without other half)
final String checkValue = new String(bytes, "UTF-8");
if (!checkValue.equals(value)) {
throw new YAMLException("invalid string value has occurred");
}
binary = Base64Coder.encode(bytes);
} catch (UnsupportedEncodingException e) {
throw new YAMLException(e);
}
value = String.valueOf(binary);
style = DumperOptions.ScalarStyle.LITERAL;
}
// if no other scalar style is explicitly set, use literal style for
// multiline scalars
if (defaultScalarStyle == DumperOptions.ScalarStyle.PLAIN && MULTILINE_PATTERN.matcher(value).find()) {
style = DumperOptions.ScalarStyle.LITERAL;
}
return representScalar(tag, value, style);
}
}
protected class RepresentBoolean implements Represent {
public Node representData(Object data) {
String value;
if (Boolean.TRUE.equals(data)) {
value = "true";
} else {
value = "false";
}
return representScalar(Tag.BOOL, value);
}
}
protected class RepresentNumber implements Represent {
public Node representData(Object data) {
Tag tag;
String value;
if (data instanceof Byte || data instanceof Short || data instanceof Integer
|| data instanceof Long || data instanceof BigInteger) {
tag = Tag.INT;
value = data.toString();
} else {
Number number = (Number) data;
tag = Tag.FLOAT;
if (number.equals(Double.NaN)) {
value = ".NaN";
} else if (number.equals(Double.POSITIVE_INFINITY)) {
value = ".inf";
} else if (number.equals(Double.NEGATIVE_INFINITY)) {
value = "-.inf";
} else {
value = number.toString();
}
}
return representScalar(getTag(data.getClass(), tag), value);
}
}
protected class RepresentList implements Represent {
@SuppressWarnings("unchecked")
public Node representData(Object data) {
return representSequence(getTag(data.getClass(), Tag.SEQ), (List<Object>) data, DumperOptions.FlowStyle.AUTO);
}
}
protected class RepresentIterator implements Represent {
@SuppressWarnings("unchecked")
public Node representData(Object data) {
Iterator<Object> iter = (Iterator<Object>) data;
return representSequence(getTag(data.getClass(), Tag.SEQ), new IteratorWrapper(iter),
DumperOptions.FlowStyle.AUTO);
}
}
private static class IteratorWrapper implements Iterable<Object> {
private Iterator<Object> iter;
public IteratorWrapper(Iterator<Object> iter) {
this.iter = iter;
}
public Iterator<Object> iterator() {
return iter;
}
}
protected class RepresentArray implements Represent {
public Node representData(Object data) {
Object[] array = (Object[]) data;
List<Object> list = Arrays.asList(array);
return representSequence(Tag.SEQ, list, DumperOptions.FlowStyle.AUTO);
}
}
/**
* Represents primitive arrays, such as short[] and float[], by converting
* them into equivalent List<Short> and List<Float> using the appropriate
* autoboxing type.
*/
protected class RepresentPrimitiveArray implements Represent {
public Node representData(Object data) {
Class<?> type = data.getClass().getComponentType();
if (byte.class == type) {
return representSequence(Tag.SEQ, asByteList(data), DumperOptions.FlowStyle.AUTO);
} else if (short.class == type) {
return representSequence(Tag.SEQ, asShortList(data), DumperOptions.FlowStyle.AUTO);
} else if (int.class == type) {
return representSequence(Tag.SEQ, asIntList(data), DumperOptions.FlowStyle.AUTO);
} else if (long.class == type) {
return representSequence(Tag.SEQ, asLongList(data), DumperOptions.FlowStyle.AUTO);
} else if (float.class == type) {
return representSequence(Tag.SEQ, asFloatList(data), DumperOptions.FlowStyle.AUTO);
} else if (double.class == type) {
return representSequence(Tag.SEQ, asDoubleList(data), DumperOptions.FlowStyle.AUTO);
} else if (char.class == type) {
return representSequence(Tag.SEQ, asCharList(data), DumperOptions.FlowStyle.AUTO);
} else if (boolean.class == type) {
return representSequence(Tag.SEQ, asBooleanList(data), DumperOptions.FlowStyle.AUTO);
}
throw new YAMLException("Unexpected primitive '" + type.getCanonicalName() + "'");
}
private List<Byte> asByteList(Object in) {
byte[] array = (byte[]) in;
List<Byte> list = new ArrayList<Byte>(array.length);
for (int i = 0; i < array.length; ++i)
list.add(array[i]);
return list;
}
private List<Short> asShortList(Object in) {
short[] array = (short[]) in;
List<Short> list = new ArrayList<Short>(array.length);
for (int i = 0; i < array.length; ++i)
list.add(array[i]);
return list;
}
private List<Integer> asIntList(Object in) {
int[] array = (int[]) in;
List<Integer> list = new ArrayList<Integer>(array.length);
for (int i = 0; i < array.length; ++i)
list.add(array[i]);
return list;
}
private List<Long> asLongList(Object in) {
long[] array = (long[]) in;
List<Long> list = new ArrayList<Long>(array.length);
for (int i = 0; i < array.length; ++i)
list.add(array[i]);
return list;
}
private List<Float> asFloatList(Object in) {
float[] array = (float[]) in;
List<Float> list = new ArrayList<Float>(array.length);
for (int i = 0; i < array.length; ++i)
list.add(array[i]);
return list;
}
private List<Double> asDoubleList(Object in) {
double[] array = (double[]) in;
List<Double> list = new ArrayList<Double>(array.length);
for (int i = 0; i < array.length; ++i)
list.add(array[i]);
return list;
}
private List<Character> asCharList(Object in) {
char[] array = (char[]) in;
List<Character> list = new ArrayList<Character>(array.length);
for (int i = 0; i < array.length; ++i)
list.add(array[i]);
return list;
}
private List<Boolean> asBooleanList(Object in) {
boolean[] array = (boolean[]) in;
List<Boolean> list = new ArrayList<Boolean>(array.length);
for (int i = 0; i < array.length; ++i)
list.add(array[i]);
return list;
}
}
protected class RepresentMap implements Represent {
@SuppressWarnings("unchecked")
public Node representData(Object data) {
return representMapping(getTag(data.getClass(), Tag.MAP), (Map<Object, Object>) data,
DumperOptions.FlowStyle.AUTO);
}
}
protected class RepresentSet implements Represent {
@SuppressWarnings("unchecked")
public Node representData(Object data) {
Map<Object, Object> value = new LinkedHashMap<Object, Object>();
Set<Object> set = (Set<Object>) data;
for (Object key : set) {
value.put(key, null);
}
return representMapping(getTag(data.getClass(), Tag.SET), value, DumperOptions.FlowStyle.AUTO);
}
}
protected class RepresentDate implements Represent {
public Node representData(Object data) {
// because SimpleDateFormat ignores timezone we have to use Calendar
Calendar calendar;
if (data instanceof Calendar) {
calendar = (Calendar) data;
} else {
calendar = Calendar.getInstance(getTimeZone() == null ? TimeZone.getTimeZone("UTC")
: timeZone);
calendar.setTime((Date) data);
}
int years = calendar.get(Calendar.YEAR);
int months = calendar.get(Calendar.MONTH) + 1; // 0..12
int days = calendar.get(Calendar.DAY_OF_MONTH); // 1..31
int hour24 = calendar.get(Calendar.HOUR_OF_DAY); // 0..24
int minutes = calendar.get(Calendar.MINUTE); // 0..59
int seconds = calendar.get(Calendar.SECOND); // 0..59
int millis = calendar.get(Calendar.MILLISECOND);
StringBuilder buffer = new StringBuilder(String.valueOf(years));
while (buffer.length() < 4) {
// ancient years
buffer.insert(0, "0");
}
buffer.append("-");
if (months < 10) {
buffer.append("0");
}
buffer.append(String.valueOf(months));
buffer.append("-");
if (days < 10) {
buffer.append("0");
}
buffer.append(String.valueOf(days));
buffer.append("T");
if (hour24 < 10) {
buffer.append("0");
}
buffer.append(String.valueOf(hour24));
buffer.append(":");
if (minutes < 10) {
buffer.append("0");
}
buffer.append(String.valueOf(minutes));
buffer.append(":");
if (seconds < 10) {
buffer.append("0");
}
buffer.append(String.valueOf(seconds));
if (millis > 0) {
if (millis < 10) {
buffer.append(".00");
} else if (millis < 100) {
buffer.append(".0");
} else {
buffer.append(".");
}
buffer.append(String.valueOf(millis));
}
// Get the offset from GMT taking DST into account
int gmtOffset = calendar.getTimeZone().getOffset(calendar.get(Calendar.ERA),
calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH), calendar.get(Calendar.DAY_OF_WEEK),
calendar.get(Calendar.MILLISECOND));
if (gmtOffset == 0) {
buffer.append('Z');
} else {
if (gmtOffset < 0) {
buffer.append('-');
gmtOffset *= -1;
} else {
buffer.append('+');
}
int minutesOffset = gmtOffset / (60 * 1000);
int hoursOffset = minutesOffset / 60;
int partOfHour = minutesOffset % 60;
if (hoursOffset < 10) {
buffer.append('0');
}
buffer.append(hoursOffset);
buffer.append(':');
if (partOfHour < 10) {
buffer.append('0');
}
buffer.append(partOfHour);
}
return representScalar(getTag(data.getClass(), Tag.TIMESTAMP), buffer.toString(), DumperOptions.ScalarStyle.PLAIN);
}
}
protected class RepresentEnum implements Represent {
public Node representData(Object data) {
Tag tag = new Tag(data.getClass());
return representScalar(getTag(data.getClass(), tag), ((Enum<?>) data).name());
}
}
protected class RepresentByteArray implements Represent {
public Node representData(Object data) {
char[] binary = Base64Coder.encode((byte[]) data);
return representScalar(Tag.BINARY, String.valueOf(binary), DumperOptions.ScalarStyle.LITERAL);
}
}
public TimeZone getTimeZone() {
return timeZone;
}
public void setTimeZone(TimeZone timeZone) {
this.timeZone = timeZone;
}
protected class RepresentUuid implements Represent {
public Node representData(Object data) {
return representScalar(getTag(data.getClass(), new Tag(UUID.class)), data.toString());
}
}
}

View File

@ -0,0 +1,138 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.resolver;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import io.jenkins.plugins.casc.snakeyaml.nodes.NodeId;
import io.jenkins.plugins.casc.snakeyaml.nodes.Tag;
/**
* Resolver tries to detect a type by content (when the tag is implicit)
*/
public class Resolver {
public static final Pattern BOOL = Pattern
.compile("^(?:yes|Yes|YES|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF)$");
/**
* The regular expression is taken from the 1.2 specification but '_'s are
* added to keep backwards compatibility
*/
public static final Pattern FLOAT = Pattern
.compile("^([-+]?(\\.[0-9]+|[0-9_]+(\\.[0-9_]*)?)([eE][-+]?[0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");
public static final Pattern INT = Pattern
.compile("^(?:[-+]?0b[0-1_]+|[-+]?0[0-7_]+|[-+]?(?:0|[1-9][0-9_]*)|[-+]?0x[0-9a-fA-F_]+|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$");
public static final Pattern MERGE = Pattern.compile("^(?:<<)$");
public static final Pattern NULL = Pattern.compile("^(?:~|null|Null|NULL| )$");
public static final Pattern EMPTY = Pattern.compile("^$");
public static final Pattern TIMESTAMP = Pattern
.compile("^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]|[0-9][0-9][0-9][0-9]-[0-9][0-9]?-[0-9][0-9]?(?:[Tt]|[ \t]+)[0-9][0-9]?:[0-9][0-9]:[0-9][0-9](?:\\.[0-9]*)?(?:[ \t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$");
public static final Pattern VALUE = Pattern.compile("^(?:=)$");
public static final Pattern YAML = Pattern.compile("^(?:!|&|\\*)$");
protected Map<Character, List<ResolverTuple>> yamlImplicitResolvers = new HashMap<Character, List<ResolverTuple>>();
protected void addImplicitResolvers() {
addImplicitResolver(Tag.BOOL, BOOL, "yYnNtTfFoO");
/*
* INT must be before FLOAT because the regular expression for FLOAT
* matches INT (see issue 130)
* http://code.google.com/p/snakeyaml/issues/detail?id=130
*/
addImplicitResolver(Tag.INT, INT, "-+0123456789");
addImplicitResolver(Tag.FLOAT, FLOAT, "-+0123456789.");
addImplicitResolver(Tag.MERGE, MERGE, "<");
addImplicitResolver(Tag.NULL, NULL, "~nN\0");
addImplicitResolver(Tag.NULL, EMPTY, null);
addImplicitResolver(Tag.TIMESTAMP, TIMESTAMP, "0123456789");
// The following implicit resolver is only for documentation
// purposes.
// It cannot work
// because plain scalars cannot start with '!', '&', or '*'.
addImplicitResolver(Tag.YAML, YAML, "!&*");
}
public Resolver() {
addImplicitResolvers();
}
public void addImplicitResolver(Tag tag, Pattern regexp, String first) {
if (first == null) {
List<ResolverTuple> curr = yamlImplicitResolvers.get(null);
if (curr == null) {
curr = new ArrayList<ResolverTuple>();
yamlImplicitResolvers.put(null, curr);
}
curr.add(new ResolverTuple(tag, regexp));
} else {
char[] chrs = first.toCharArray();
for (int i = 0, j = chrs.length; i < j; i++) {
Character theC = Character.valueOf(chrs[i]);
if (theC == 0) {
// special case: for null
theC = null;
}
List<ResolverTuple> curr = yamlImplicitResolvers.get(theC);
if (curr == null) {
curr = new ArrayList<ResolverTuple>();
yamlImplicitResolvers.put(theC, curr);
}
curr.add(new ResolverTuple(tag, regexp));
}
}
}
public Tag resolve(NodeId kind, String value, boolean implicit) {
if (kind == NodeId.scalar && implicit) {
final List<ResolverTuple> resolvers;
if (value.length() == 0) {
resolvers = yamlImplicitResolvers.get('\0');
} else {
resolvers = yamlImplicitResolvers.get(value.charAt(0));
}
if (resolvers != null) {
for (ResolverTuple v : resolvers) {
Tag tag = v.getTag();
Pattern regexp = v.getRegexp();
if (regexp.matcher(value).matches()) {
return tag;
}
}
}
if (yamlImplicitResolvers.containsKey(null)) {
for (ResolverTuple v : yamlImplicitResolvers.get(null)) {
Tag tag = v.getTag();
Pattern regexp = v.getRegexp();
if (regexp.matcher(value).matches()) {
return tag;
}
}
}
}
switch (kind) {
case scalar:
return Tag.STR;
case sequence:
return Tag.SEQ;
default:
return Tag.MAP;
}
}
}

View File

@ -0,0 +1,43 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.resolver;
import java.util.regex.Pattern;
import io.jenkins.plugins.casc.snakeyaml.nodes.Tag;
final class ResolverTuple {
private final Tag tag;
private final Pattern regexp;
public ResolverTuple(Tag tag, Pattern regexp) {
this.tag = tag;
this.regexp = regexp;
}
public Tag getTag() {
return tag;
}
public Pattern getRegexp() {
return regexp;
}
@Override
public String toString() {
return "Tuple tag=" + tag + " regexp=" + regexp;
}
}

View File

@ -0,0 +1,76 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.scanner;
import java.util.Arrays;
public final class Constant {
private final static String ALPHA_S = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
private final static String LINEBR_S = "\n\u0085\u2028\u2029";
private final static String FULL_LINEBR_S = "\r" + LINEBR_S;
private final static String NULL_OR_LINEBR_S = "\0" + FULL_LINEBR_S;
private final static String NULL_BL_LINEBR_S = " " + NULL_OR_LINEBR_S;
private final static String NULL_BL_T_LINEBR_S = "\t" + NULL_BL_LINEBR_S;
private final static String NULL_BL_T_S = "\0 \t";
private final static String URI_CHARS_S = ALPHA_S + "-;/?:@&=+$,_.!~*\'()[]%";
public final static Constant LINEBR = new Constant(LINEBR_S);
public final static Constant FULL_LINEBR = new Constant(FULL_LINEBR_S);
public final static Constant NULL_OR_LINEBR = new Constant(NULL_OR_LINEBR_S);
public final static Constant NULL_BL_LINEBR = new Constant(NULL_BL_LINEBR_S);
public final static Constant NULL_BL_T_LINEBR = new Constant(NULL_BL_T_LINEBR_S);
public final static Constant NULL_BL_T = new Constant(NULL_BL_T_S);
public final static Constant URI_CHARS = new Constant(URI_CHARS_S);
public final static Constant ALPHA = new Constant(ALPHA_S);
private String content;
boolean[] contains = new boolean[128];
boolean noASCII = false;
private Constant(String content) {
Arrays.fill(contains, false);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < content.length(); i++) {
int c = content.codePointAt(i);
if (c < 128)
contains[c] = true;
else
sb.appendCodePoint(c);
}
if (sb.length() > 0) {
noASCII = true;
this.content = sb.toString();
}
}
public boolean has(int c) {
return (c < 128) ? contains[c] : noASCII && content.indexOf(c, 0) != -1;
}
public boolean hasNo(int c) {
return !has(c);
}
public boolean has(int c, String additional) {
return has(c) || additional.indexOf(c, 0) != -1;
}
public boolean hasNo(int c, String additional) {
return !has(c, additional);
}
}

View File

@ -0,0 +1,67 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.scanner;
import io.jenkins.plugins.casc.snakeyaml.tokens.Token;
/**
* This interface represents an input stream of {@link Token}s.
* <p>
* The parser and the scanner form together the 'Parse' step in the loading
* process (see chapter 3.1 of the <a href="http://yaml.org/spec/1.1/">YAML
* Specification</a>).
* </p>
*
* @see io.jenkins.plugins.casc.snakeyaml.tokens.Token
*/
public interface Scanner {
/**
* Check if the next token is one of the given types.
*
* @param choices
* token IDs.
* @return <code>true</code> if the next token can be assigned to a variable
* of at least one of the given types. Returns <code>false</code> if
* no more tokens are available.
* @throws ScannerException
* Thrown in case of malformed input.
*/
boolean checkToken(Token.ID... choices);
/**
* Return the next token, but do not delete it from the stream.
* The method must be called only after {@link #checkToken}.
*
* @return The token that will be returned on the next call to {@link #getToken}
* @throws ScannerException Thrown in case of malformed input.
* @throws IndexOutOfBoundsException if no more token left
*/
Token peekToken();
/**
* Returns the next token.
* <p>
* The token will be removed from the stream.
* (Every invocation of this method must happen after calling {@link #checkToken}.
* </p>
*
* @return the coming token
* @throws ScannerException Thrown in case of malformed input.
* @throws IndexOutOfBoundsException if no more token left
*/
Token getToken();
}

View File

@ -0,0 +1,66 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.scanner;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
import io.jenkins.plugins.casc.snakeyaml.error.MarkedYAMLException;
/**
* Exception thrown by the {@link Scanner} implementations in case of malformed
* input.
*/
public class ScannerException extends MarkedYAMLException {
private static final long serialVersionUID = 4782293188600445954L;
/**
* Constructs an instance.
*
* @param context
* Part of the input document in which vicinity the problem
* occurred.
* @param contextMark
* Position of the <code>context</code> within the document.
* @param problem
* Part of the input document that caused the problem.
* @param problemMark
* Position of the <code>problem</code> within the document.
* @param note
* Message for the user with further information about the
* problem.
*/
public ScannerException(String context, Mark contextMark, String problem, Mark problemMark,
String note) {
super(context, contextMark, problem, problemMark, note);
}
/**
* Constructs an instance.
*
* @param context
* Part of the input document in which vicinity the problem
* occurred.
* @param contextMark
* Position of the <code>context</code> within the document.
* @param problem
* Part of the input document that caused the problem.
* @param problemMark
* Position of the <code>problem</code> within the document.
*/
public ScannerException(String context, Mark contextMark, String problem, Mark problemMark) {
this(context, contextMark, problem, problemMark, null);
}
}

View File

@ -0,0 +1,74 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.scanner;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* Simple keys treatment.
* <p>
* Helper class for {@link ScannerImpl}.
* </p>
*
* @see ScannerImpl
*/
final class SimpleKey {
private int tokenNumber;
private boolean required;
private int index;
private int line;
private int column;
private Mark mark;
public SimpleKey(int tokenNumber, boolean required, int index, int line, int column, Mark mark) {
this.tokenNumber = tokenNumber;
this.required = required;
this.index = index;
this.line = line;
this.column = column;
this.mark = mark;
}
public int getTokenNumber() {
return this.tokenNumber;
}
public int getColumn() {
return this.column;
}
public Mark getMark() {
return mark;
}
public int getIndex() {
return index;
}
public int getLine() {
return line;
}
public boolean isRequired() {
return required;
}
@Override
public String toString() {
return "SimpleKey - tokenNumber=" + tokenNumber + " required=" + required + " index="
+ index + " line=" + line + " column=" + column;
}
}

View File

@ -0,0 +1,23 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.serializer;
import io.jenkins.plugins.casc.snakeyaml.nodes.Node;
public interface AnchorGenerator {
String nextAnchor(Node node);
}

View File

@ -0,0 +1,39 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.serializer;
import io.jenkins.plugins.casc.snakeyaml.nodes.Node;
import java.text.NumberFormat;
public class NumberAnchorGenerator implements AnchorGenerator {
private int lastAnchorId = 0;
public NumberAnchorGenerator(int lastAnchorId) {
this.lastAnchorId = lastAnchorId;
}
public String nextAnchor(Node node) {
this.lastAnchorId++;
NumberFormat format = NumberFormat.getNumberInstance();
format.setMinimumIntegerDigits(3);
format.setMaximumFractionDigits(0);// issue 172
format.setGroupingUsed(false);
String anchorId = format.format(this.lastAnchorId);
return "id" + anchorId;
}
}

View File

@ -0,0 +1,201 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.serializer;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions;
import io.jenkins.plugins.casc.snakeyaml.DumperOptions.Version;
import io.jenkins.plugins.casc.snakeyaml.emitter.Emitable;
import io.jenkins.plugins.casc.snakeyaml.events.AliasEvent;
import io.jenkins.plugins.casc.snakeyaml.events.DocumentEndEvent;
import io.jenkins.plugins.casc.snakeyaml.events.DocumentStartEvent;
import io.jenkins.plugins.casc.snakeyaml.events.ImplicitTuple;
import io.jenkins.plugins.casc.snakeyaml.events.MappingEndEvent;
import io.jenkins.plugins.casc.snakeyaml.events.MappingStartEvent;
import io.jenkins.plugins.casc.snakeyaml.events.ScalarEvent;
import io.jenkins.plugins.casc.snakeyaml.events.SequenceEndEvent;
import io.jenkins.plugins.casc.snakeyaml.events.SequenceStartEvent;
import io.jenkins.plugins.casc.snakeyaml.events.StreamEndEvent;
import io.jenkins.plugins.casc.snakeyaml.events.StreamStartEvent;
import io.jenkins.plugins.casc.snakeyaml.nodes.AnchorNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.CollectionNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.MappingNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.Node;
import io.jenkins.plugins.casc.snakeyaml.nodes.NodeId;
import io.jenkins.plugins.casc.snakeyaml.nodes.NodeTuple;
import io.jenkins.plugins.casc.snakeyaml.nodes.ScalarNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.SequenceNode;
import io.jenkins.plugins.casc.snakeyaml.nodes.Tag;
import io.jenkins.plugins.casc.snakeyaml.resolver.Resolver;
public final class Serializer {
private final Emitable emitter;
private final Resolver resolver;
private boolean explicitStart;
private boolean explicitEnd;
private Version useVersion;
private Map<String, String> useTags;
private Set<Node> serializedNodes;
private Map<Node, String> anchors;
private AnchorGenerator anchorGenerator;
private Boolean closed;
private Tag explicitRoot;
public Serializer(Emitable emitter, Resolver resolver, DumperOptions opts, Tag rootTag) {
this.emitter = emitter;
this.resolver = resolver;
this.explicitStart = opts.isExplicitStart();
this.explicitEnd = opts.isExplicitEnd();
if (opts.getVersion() != null) {
this.useVersion = opts.getVersion();
}
this.useTags = opts.getTags();
this.serializedNodes = new HashSet<Node>();
this.anchors = new HashMap<Node, String>();
this.anchorGenerator = opts.getAnchorGenerator();
this.closed = null;
this.explicitRoot = rootTag;
}
public void open() throws IOException {
if (closed == null) {
this.emitter.emit(new StreamStartEvent(null, null));
this.closed = Boolean.FALSE;
} else if (Boolean.TRUE.equals(closed)) {
throw new SerializerException("serializer is closed");
} else {
throw new SerializerException("serializer is already opened");
}
}
public void close() throws IOException {
if (closed == null) {
throw new SerializerException("serializer is not opened");
} else if (!Boolean.TRUE.equals(closed)) {
this.emitter.emit(new StreamEndEvent(null, null));
this.closed = Boolean.TRUE;
}
}
public void serialize(Node node) throws IOException {
if (closed == null) {
throw new SerializerException("serializer is not opened");
} else if (closed) {
throw new SerializerException("serializer is closed");
}
this.emitter.emit(new DocumentStartEvent(null, null, this.explicitStart, this.useVersion,
useTags));
anchorNode(node);
if (explicitRoot != null) {
node.setTag(explicitRoot);
}
serializeNode(node, null);
this.emitter.emit(new DocumentEndEvent(null, null, this.explicitEnd));
this.serializedNodes.clear();
this.anchors.clear();
}
private void anchorNode(Node node) {
if (node.getNodeId() == NodeId.anchor) {
node = ((AnchorNode) node).getRealNode();
}
if (this.anchors.containsKey(node)) {
String anchor = this.anchors.get(node);
if (null == anchor) {
anchor = this.anchorGenerator.nextAnchor(node);
this.anchors.put(node, anchor);
}
} else {
this.anchors.put(node, null);
switch (node.getNodeId()) {
case sequence:
SequenceNode seqNode = (SequenceNode) node;
List<Node> list = seqNode.getValue();
for (Node item : list) {
anchorNode(item);
}
break;
case mapping:
MappingNode mnode = (MappingNode) node;
List<NodeTuple> map = mnode.getValue();
for (NodeTuple object : map) {
Node key = object.getKeyNode();
Node value = object.getValueNode();
anchorNode(key);
anchorNode(value);
}
break;
}
}
}
//parent Node is not used but might be used in the future
private void serializeNode(Node node, Node parent) throws IOException {
if (node.getNodeId() == NodeId.anchor) {
node = ((AnchorNode) node).getRealNode();
}
String tAlias = this.anchors.get(node);
if (this.serializedNodes.contains(node)) {
this.emitter.emit(new AliasEvent(tAlias, null, null));
} else {
this.serializedNodes.add(node);
switch (node.getNodeId()) {
case scalar:
ScalarNode scalarNode = (ScalarNode) node;
Tag detectedTag = this.resolver.resolve(NodeId.scalar, scalarNode.getValue(), true);
Tag defaultTag = this.resolver.resolve(NodeId.scalar, scalarNode.getValue(), false);
ImplicitTuple tuple = new ImplicitTuple(node.getTag().equals(detectedTag), node
.getTag().equals(defaultTag));
ScalarEvent event = new ScalarEvent(tAlias, node.getTag().getValue(), tuple,
scalarNode.getValue(), null, null, scalarNode.getStyle());
this.emitter.emit(event);
break;
case sequence:
SequenceNode seqNode = (SequenceNode) node;
boolean implicitS = node.getTag().equals(this.resolver.resolve(NodeId.sequence,
null, true));
this.emitter.emit(new SequenceStartEvent(tAlias, node.getTag().getValue(),
implicitS, null, null, seqNode.getFlowStyle()));
List<Node> list = seqNode.getValue();
for (Node item : list) {
serializeNode(item, node);
}
this.emitter.emit(new SequenceEndEvent(null, null));
break;
default:// instance of MappingNode
Tag implicitTag = this.resolver.resolve(NodeId.mapping, null, true);
boolean implicitM = node.getTag().equals(implicitTag);
this.emitter.emit(new MappingStartEvent(tAlias, node.getTag().getValue(),
implicitM, null, null, ((CollectionNode) node).getFlowStyle()));
MappingNode mnode = (MappingNode) node;
List<NodeTuple> map = mnode.getValue();
for (NodeTuple row : map) {
Node key = row.getKeyNode();
Node value = row.getValueNode();
serializeNode(key, mnode);
serializeNode(value, mnode);
}
this.emitter.emit(new MappingEndEvent(null, null));
}
}
}
}

View File

@ -0,0 +1,26 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.serializer;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
public class SerializerException extends YAMLException {
private static final long serialVersionUID = 2632638197498912433L;
public SerializerException(String message) {
super(message);
}
}

View File

@ -0,0 +1,36 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.tokens;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
public final class AliasToken extends Token {
private final String value;
public AliasToken(String value, Mark startMark, Mark endMark) {
super(startMark, endMark);
this.value = value;
}
public String getValue() {
return this.value;
}
@Override
public Token.ID getTokenId() {
return ID.Alias;
}
}

View File

@ -0,0 +1,36 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.tokens;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
public final class AnchorToken extends Token {
private final String value;
public AnchorToken(String value, Mark startMark, Mark endMark) {
super(startMark, endMark);
this.value = value;
}
public String getValue() {
return this.value;
}
@Override
public Token.ID getTokenId() {
return ID.Anchor;
}
}

View File

@ -0,0 +1,30 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.tokens;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
public final class BlockEndToken extends Token {
public BlockEndToken(Mark startMark, Mark endMark) {
super(startMark, endMark);
}
@Override
public Token.ID getTokenId() {
return ID.BlockEnd;
}
}

View File

@ -0,0 +1,30 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.tokens;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
public final class BlockEntryToken extends Token {
public BlockEntryToken(Mark startMark, Mark endMark) {
super(startMark, endMark);
}
@Override
public Token.ID getTokenId() {
return ID.BlockEntry;
}
}

View File

@ -0,0 +1,30 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.tokens;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
public final class BlockMappingStartToken extends Token {
public BlockMappingStartToken(Mark startMark, Mark endMark) {
super(startMark, endMark);
}
@Override
public Token.ID getTokenId() {
return ID.BlockMappingStart;
}
}

View File

@ -0,0 +1,30 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.tokens;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
public final class BlockSequenceStartToken extends Token {
public BlockSequenceStartToken(Mark startMark, Mark endMark) {
super(startMark, endMark);
}
@Override
public Token.ID getTokenId() {
return ID.BlockSequenceStart;
}
}

View File

@ -0,0 +1,32 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.tokens;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
/**
* @deprecated it will be removed because it is not used
*/
public class CommentToken extends Token {
public CommentToken(Mark startMark, Mark endMark) {
super(startMark, endMark);
}
@Override
public ID getTokenId() {
return ID.Comment;
}
}

View File

@ -0,0 +1,49 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.tokens;
import java.util.List;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
import io.jenkins.plugins.casc.snakeyaml.error.YAMLException;
public final class DirectiveToken<T> extends Token {
private final String name;
private final List<T> value;
public DirectiveToken(String name, List<T> value, Mark startMark, Mark endMark) {
super(startMark, endMark);
this.name = name;
if (value != null && value.size() != 2) {
throw new YAMLException("Two strings must be provided instead of "
+ String.valueOf(value.size()));
}
this.value = value;
}
public String getName() {
return this.name;
}
public List<T> getValue() {
return this.value;
}
@Override
public Token.ID getTokenId() {
return ID.Directive;
}
}

View File

@ -0,0 +1,30 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jenkins.plugins.casc.snakeyaml.tokens;
import io.jenkins.plugins.casc.snakeyaml.error.Mark;
public final class DocumentEndToken extends Token {
public DocumentEndToken(Mark startMark, Mark endMark) {
super(startMark, endMark);
}
@Override
public Token.ID getTokenId() {
return ID.DocumentEnd;
}
}

Some files were not shown because too many files have changed in this diff Show More