diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..6e7a655 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,51 @@ +name: CI + +on: + push: + branches: [ master ] + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # JVM the built plugin is tested on (Gradle itself needs JDK 17+) + test-java: [ 11, 17, 21 ] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: temurin + # The last one (21) becomes default JAVA_HOME and runs Gradle, the other is found by toolchains + java-version: | + ${{ matrix.test-java }} + 21 + - uses: gradle/actions/setup-gradle@v4 + - name: Build and test on Java ${{ matrix.test-java }} + run: ./gradlew check --rerun-tasks -PtestJavaVersion=${{ matrix.test-java }} + - name: Upload test report + if: failure() + uses: actions/upload-artifact@v4 + with: + name: test-report-java-${{ matrix.test-java }} + path: build/reports/tests/ + + example: + # Example project depends on the plugin built from this very commit + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: | + 11 + 21 + - uses: gradle/actions/setup-gradle@v4 + - name: Publish plugin into local Maven repository + run: ./gradlew publishToMavenLocal + - name: Build and test example project + working-directory: example-project-gradle + run: ./gradlew check --rerun-tasks -PuseMavenLocal diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 2060638..0000000 --- a/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -# https://docs.travis-ci.com/user/languages/groovy/ -language: groovy -jdk: - - openjdk11 - -script: ./gradlew check --rerun-tasks - -before_cache: - - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock -cache: - directories: - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ diff --git a/README.md b/README.md index cf34465..92bb336 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Autobuild Status](https://travis-ci.org/Hubbitus/xjc-documentation-annotation-plugin.svg?branch=master)](https://travis-ci.org/Hubbitus/xjc-documentation-annotation-plugin) +[![CI](https://github.com/Hubbitus/xjc-documentation-annotation-plugin/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/Hubbitus/xjc-documentation-annotation-plugin/actions/workflows/ci.yml) XJC plugin to bring XSD descriptions into annotations of generated classes ========================================================================== diff --git a/build.gradle b/build.gradle index d6f4713..f7e3ea2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,104 +1,128 @@ plugins { - id 'java' + id 'java-library' id 'groovy' // Testing // http://central.sonatype.org/pages/gradle.html - id 'maven' + id 'maven-publish' id 'idea' id 'signing' } -group 'info.hubbitus' -version '1.1' +group = 'info.hubbitus' +version = '1.2-SNAPSHOT' // 1.1 is released and has the NPE bug (#2), the fix is in the next version -sourceCompatibility = 1.8 +// Gradle itself requires JDK 17+, but the built plugin must work on Java 11+ +java { + // Also used for Groovy (tests) bytecode level, which otherwise defaults to the JVM running Gradle + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' + options.release = 11 +} + +tasks.withType(Test).configureEach { + useJUnitPlatform() // Spock 2 +} + +// Run tests on a specific JVM (to check that built plugin works on it): ./gradlew test -PtestJavaVersion=11 +if (project.hasProperty('testJavaVersion')) { + tasks.withType(Test).configureEach { + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(project.property('testJavaVersion') as int) + } + } +} + +tasks.withType(Javadoc).configureEach { + options.encoding = 'UTF-8' +} repositories { mavenCentral() } dependencies { - compile 'com.sun.xml.bind:jaxb-core:2.3.0.1' - compile "javax.xml.bind:jaxb-api:${versionJaxbIpi}" - testCompile "javax.xml.bind:jaxb-api:${versionJaxbIpi}" - compile "com.sun.xml.bind:jaxb-xjc:${versionJaxb}" - compile "com.sun.xml.bind:jaxb-impl:${versionJaxb}" + api 'com.sun.xml.bind:jaxb-core:2.3.0.1' + api "javax.xml.bind:jaxb-api:${versionJaxbIpi}" + testImplementation "javax.xml.bind:jaxb-api:${versionJaxbIpi}" + implementation "com.sun.xml.bind:jaxb-xjc:${versionJaxb}" + implementation "com.sun.xml.bind:jaxb-impl:${versionJaxb}" // Logging - compile "org.slf4j:slf4j-api:${versionSlf4j}" - compile "ch.qos.logback:logback-classic:${versionLogback}" + implementation "org.slf4j:slf4j-api:${versionSlf4j}" + implementation "ch.qos.logback:logback-classic:${versionLogback}" - testCompile "org.codehaus.groovy:groovy:${versionGroovy}" - testCompile "org.spockframework:spock-core:${versionSpock}" + testImplementation "org.apache.groovy:groovy:${versionGroovy}" + testImplementation "org.spockframework:spock-core:${versionSpock}" + testRuntimeOnly "org.junit.platform:junit-platform-launcher" // Required by Gradle 9 for JUnit Platform (version is managed by Spock BOM) } /////////////////////////////////////////////////////////////// // Artifacts publishing into central OSS repository // http://central.sonatype.org/pages/gradle.html -task javadocJar(type: Jar) { - archiveClassifier.set('javadoc') // https://discuss.gradle.org/t/publishing-jars-with-classifiers-after-v5-0/30144/2 - from javadoc -} - -task sourcesJar(type: Jar) { - archiveClassifier.set('sources') - from sourceSets.main.allSource -} - -artifacts { - archives javadocJar, sourcesJar -} -signing { - required { gradle.taskGraph.hasTask("uploadArchives") } // https://groups.google.com/forum/#!topic/gaelyk/WfdEDBOzIOM - sign configurations.archives -} +def ossrhUserName = project.findProperty('ossrhUsername') ?: '' // To do not fail on CI when them does not defined +def ossrhPassword = project.findProperty('ossrhPassword') ?: '' -ext{// To do not fail on CI when them does not defined - ossrhUser = (project.hasProperty('ossrhUsername') ? project.property('ossrhUsername') : '') - ossrhPass = (project.hasProperty('ossrhPassword') ? project.property('ossrhPassword') : '') +java { + withJavadocJar() + withSourcesJar() } -uploadArchives { - repositories { - mavenDeployer { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - - repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { - authentication(userName: ossrhUser, password: ossrhPass) - } - - snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { - authentication(userName: ossrhUser, password: ossrhPass) - } +publishing { + publications { + mavenJava(MavenPublication) { + from components.java - pom.project { - name project.name - packaging 'jar' - description 'XJC plugin to bring XSD descriptions into annotations of generated classes' - url 'https://github.com/Hubbitus/xjc-documentation-annotation-plugin' + pom { + name = project.name + packaging = 'jar' + description = 'XJC plugin to bring XSD descriptions into annotations of generated classes' + url = 'https://github.com/Hubbitus/xjc-documentation-annotation-plugin' scm { - connection 'scm:git:https://github.com/Hubbitus/xjc-documentation-annotation-plugin.git' - developerConnection 'scm:git:git@github.com:Hubbitus/xjc-documentation-annotation-plugin.git' - url 'https://github.com/Hubbitus/xjc-documentation-annotation-plugin' + connection = 'scm:git:https://github.com/Hubbitus/xjc-documentation-annotation-plugin.git' + developerConnection = 'scm:git:git@github.com:Hubbitus/xjc-documentation-annotation-plugin.git' + url = 'https://github.com/Hubbitus/xjc-documentation-annotation-plugin' } licenses { license { - name 'MIT' - url 'https://opensource.org/licenses/MIT' + name = 'MIT' + url = 'https://opensource.org/licenses/MIT' } } developers { developer { - id 'Hubbitus' - name 'Pavel Alexeev' - email 'Pahan@Hubbitus.info' + id = 'Hubbitus' + name = 'Pavel Alexeev' + email = 'Pahan@Hubbitus.info' } } } } } + + repositories { + maven { + name = 'ossrh' + def releasesRepoUrl = uri('https://oss.sonatype.org/service/local/staging/deploy/maven2/') + def snapshotsRepoUrl = uri('https://oss.sonatype.org/content/repositories/snapshots/') + url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl + credentials { + username = ossrhUserName + password = ossrhPassword + } + } + } } + +signing { + required = { gradle.taskGraph.hasTask('publish') } // Do not require signing on CI/local builds + sign publishing.publications.mavenJava +} + // /Artifacts publishing into central OSS repository //////////////////////////////////////////////////// diff --git a/example-project-gradle/README.md b/example-project-gradle/README.md index 8455a8b..93487a8 100644 --- a/example-project-gradle/README.md +++ b/example-project-gradle/README.md @@ -6,10 +6,16 @@ This is gradle demo project to show how to use Java code generation from XSD sch For run generation just invoke: - ./gradlew xjcGenerate + ./gradlew xjc -After compilation you will find generated classes in [src/main/generated-java](src/main/generated-java) +After compilation you will find generated classes in `build/generated/sources/xjc/java` Then you may with run tests: ./gradlew check + +While the plugin version from [build.gradle](build.gradle) is not released yet, publish it into the local Maven repository +from the parent project and use it with `-PuseMavenLocal`: + + (cd .. && ./gradlew publishToMavenLocal) + ./gradlew check -PuseMavenLocal diff --git a/example-project-gradle/build.gradle b/example-project-gradle/build.gradle index 9931bde..b95838e 100644 --- a/example-project-gradle/build.gradle +++ b/example-project-gradle/build.gradle @@ -1,58 +1,56 @@ plugins { id 'java' - id 'org.unbroken-dome.xjc' version '1.4.1' // https://github.com/unbroken-dome/gradle-xjc-plugin + id 'com.github.bjornvester.xjc' version '1.9.1' // https://github.com/bjornvester/xjc-gradle-plugin id 'idea' id 'groovy' // For Spock tests } -group 'info.hubbitus' -version '1.0-SNAPSHOT' +group = 'info.hubbitus' +version = '1.0-SNAPSHOT' -sourceCompatibility = 1.8 +java { + toolchain { languageVersion = JavaLanguageVersion.of(11) } +} repositories { mavenCentral() + if (project.hasProperty('useMavenLocal')) { + // To try the not yet released plugin, published by `./gradlew publishToMavenLocal` in the parent project + mavenLocal() + } } ext{ - pluginVersion = '1.1' + pluginVersion = '1.2-SNAPSHOT' // Includes the fix of #2. Set to the released version (e.g. '1.2') once it is available on Maven Central } dependencies { - xjcClasspath "info.hubbitus:xjc-documentation-annotation-plugin:$pluginVersion" + xjcPlugins "info.hubbitus:xjc-documentation-annotation-plugin:$pluginVersion" // Compile dependency for annotations used - compile "info.hubbitus:xjc-documentation-annotation-plugin:$pluginVersion" - testCompile "info.hubbitus:xjc-documentation-annotation-plugin:$pluginVersion" + implementation "info.hubbitus:xjc-documentation-annotation-plugin:$pluginVersion" + testImplementation "info.hubbitus:xjc-documentation-annotation-plugin:$pluginVersion" // Tests - testCompile 'org.codehaus.groovy:groovy:2.5.5' - testCompile 'org.spockframework:spock-core:1.2-groovy-2.5' + testImplementation 'org.apache.groovy:groovy:5.1.3' + testImplementation 'org.spockframework:spock-core:2.4-groovy-5.0' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' // Required by Gradle 9 (version is managed by Spock BOM) +} + +tasks.withType(Test).configureEach { + useJUnitPlatform() // Spock 2 } -// Results will be in directory `src/main/generated-java` -xjcGenerate { +// Results will be in directory `build/generated/sources/xjc/java` +xjc { /** * There: * 1. Example.xsd is minimal example of functional. * 2. maven-4.0.0.xsd - example by SOq https://stackoverflow.com/questions/42223784/how-can-i-generate-a-class-from-which-i-can-retrieve-the-xml-of-a-node-as-a-stri */ - source = fileTree('src/main/resources') { include '*.xsd' } - bindingFiles = fileTree('src/main/jaxb') { include '*.xjb' } - outputDirectory = file('src/main/generated-java') - packageLevelAnnotations = false - targetPackage = 'info.hubbitus.xjc.plugin.example' - extraArgs = [ '-XPluginDescriptionAnnotation' ] + xsdDir = layout.projectDirectory.dir('src/main/resources') + bindingFiles = fileTree('src/main/resources') { include '*.xjb' } + useJakarta = false // The plugin is built on javax (JAXB 2.x) XJC API + defaultPackage = 'info.hubbitus.xjc.plugin.example' + options = [ '-XPluginDescriptionAnnotation' ] } - -// Add generated files into compilation: -// https://stackoverflow.com/questions/36749015/how-do-i-get-intellij-to-recognize-gradle-generated-sources-dir/44740130#44740130 -sourceSets.main.java.srcDir new File(buildDir, xjcGenerate.outputDirectory.absolutePath) -idea { - module { - // Marks the already(!) added srcDir as "generated" - generatedSourceDirs += xjcGenerate.outputDirectory - } -} - -compileTestGroovy.dependsOn xjcGenerate diff --git a/example-project-gradle/gradle/wrapper/gradle-wrapper.jar b/example-project-gradle/gradle/wrapper/gradle-wrapper.jar index 28861d2..5097068 100644 Binary files a/example-project-gradle/gradle/wrapper/gradle-wrapper.jar and b/example-project-gradle/gradle/wrapper/gradle-wrapper.jar differ diff --git a/example-project-gradle/gradle/wrapper/gradle-wrapper.properties b/example-project-gradle/gradle/wrapper/gradle-wrapper.properties index 6ac6476..9b7cb4a 100644 --- a/example-project-gradle/gradle/wrapper/gradle-wrapper.properties +++ b/example-project-gradle/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,9 @@ -#Mon Jan 28 02:58:37 MSK 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.0-bin.zip +networkTimeout=10000 +retries=0 +retryBackOffMs=500 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip diff --git a/example-project-gradle/gradlew b/example-project-gradle/gradlew index cccdd3d..249efbb 100755 --- a/example-project-gradle/gradlew +++ b/example-project-gradle/gradlew @@ -1,78 +1,128 @@ -#!/usr/bin/env sh +#!/bin/sh + +# +# Copyright © 2015 the original authors. +# +# 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 +# +# https://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. +# +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# gradlew start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh gradlew +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -81,92 +131,118 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" fi +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + exec "$JAVACMD" "$@" diff --git a/example-project-gradle/gradlew.bat b/example-project-gradle/gradlew.bat index f955316..03754c4 100644 --- a/example-project-gradle/gradlew.bat +++ b/example-project-gradle/gradlew.bat @@ -1,84 +1,112 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem gradlew startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions + +@rem Catch executions from older scripts and ensure they exit cleanly. +@rem This can be removed once we can be reasonably confident that few people +@rem will be migrating directly to this new wrapper. +goto afterSafetyNet +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +goto exitWithErrorLevel +:afterSafetyNet + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +1>&2 echo. +1>&2 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +1>&2 echo. +1>&2 echo Please set the JAVA_HOME variable in your environment to match the +1>&2 echo location of your Java installation. + +"%COMSPEC%" /c exit 1 +goto exitWithErrorLevel + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +1>&2 echo. +1>&2 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +1>&2 echo. +1>&2 echo Please set the JAVA_HOME variable in your environment to match the +1>&2 echo location of your Java installation. + +"%COMSPEC%" /c exit 1 +goto exitWithErrorLevel + +:execute +@rem Setup the command line + + + +@rem Execute gradlew +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel & goto exitWithErrorLevel + +@rem This label must not be changed. We rely on old scripts being able to jump to this point. +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/gradle.properties b/gradle.properties index 861ccfc..aa2a9b5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,9 +1,8 @@ versionJaxb = 2.4.0-b180830.0438 versionJaxbIpi = 2.4.0-b180830.0359 -#versionGroovy = 3.0.0-alpha-4 -versionGroovy = 2.5.5 -versionSpock = 1.2-groovy-2.5 +versionGroovy = 5.1.3 +versionSpock = 2.4-groovy-5.0 versionSlf4j = 1.7.25 versionLogback = 1.2.3 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 87b738c..1b33c55 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b7c8c5d..299848b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.0-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index af6708f..23d15a9 100755 --- a/gradlew +++ b/gradlew @@ -1,78 +1,129 @@ -#!/usr/bin/env sh +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# 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 +# +# https://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. +# +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -81,92 +132,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" fi +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 6d57edc..5eed7ee 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,84 +1,94 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH= + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/java/info/hubbitus/JStringLiteralUnescaped.java b/src/main/java/info/hubbitus/JStringLiteralUnescaped.java index 64bf429..065e77d 100644 --- a/src/main/java/info/hubbitus/JStringLiteralUnescaped.java +++ b/src/main/java/info/hubbitus/JStringLiteralUnescaped.java @@ -13,6 +13,7 @@ */ public class JStringLiteralUnescaped extends JExpressionImpl { + /** Raw (not yet quoted and escaped) string value of this literal. */ public final String str; diff --git a/src/main/java/info/hubbitus/XJCPluginDescriptionAnnotation.java b/src/main/java/info/hubbitus/XJCPluginDescriptionAnnotation.java index e2b9dcc..ec9e378 100644 --- a/src/main/java/info/hubbitus/XJCPluginDescriptionAnnotation.java +++ b/src/main/java/info/hubbitus/XJCPluginDescriptionAnnotation.java @@ -19,6 +19,7 @@ import com.sun.tools.xjc.outline.ClassOutline; import com.sun.tools.xjc.outline.Outline; import com.sun.tools.xjc.reader.xmlschema.bindinfo.BindInfo; +import com.sun.xml.xsom.XSAnnotation; import com.sun.xml.xsom.XSComponent; import com.sun.xml.xsom.impl.AttributeUseImpl; import com.sun.xml.xsom.impl.ParticleImpl; @@ -78,6 +79,14 @@ * @since 2019-01-17 03:34. */ public class XJCPluginDescriptionAnnotation extends Plugin { + /** + * Public no-arg constructor is required by XJC, which instantiates plugins via {@link java.util.ServiceLoader} + * (see META-INF/services/com.sun.tools.xjc.Plugin). + */ + public XJCPluginDescriptionAnnotation() { + super(); + } + @Override public String getOptionName() { return "XPluginDescriptionAnnotation"; @@ -170,33 +179,38 @@ private static Object getPrivateField(Object obj, String fieldName) { } static private String classInfoGetDescriptionAnnotation(CClassInfo classInfo){ - String description = ""; - if (null != (classInfo.getSchemaComponent()).getAnnotation()){ - description = ((BindInfo)(classInfo.getSchemaComponent()).getAnnotation().getAnnotation()).getDocumentation(); - } - return description.trim(); + return resolveDescription(classInfo.getSchemaComponent().getAnnotation()); } static private String fieldGetDescriptionAnnotation(CPropertyInfo propertyInfo){ - String description = ""; - assert ( (propertyInfo.getSchemaComponent() instanceof AttributeUseImpl) || (propertyInfo.getSchemaComponent() instanceof ParticleImpl) ); + XSComponent schemaComponent = propertyInfo.getSchemaComponent(); + XSAnnotation annotation = null; // // // // Идентификатор документа - if ( (propertyInfo.getSchemaComponent() instanceof AttributeUseImpl) - && null != ( ((AttributeUseImpl)propertyInfo.getSchemaComponent()).getDecl().getAnnotation() )){ - description = ((BindInfo)((AttributeUseImpl)propertyInfo.getSchemaComponent()).getDecl().getAnnotation().getAnnotation()).getDocumentation(); + if (schemaComponent instanceof AttributeUseImpl){ + annotation = ((AttributeUseImpl)schemaComponent).getDecl().getAnnotation(); } // // // // Заголовок заявления - if ( (propertyInfo.getSchemaComponent() instanceof ParticleImpl) - && null != ( (((ParticleImpl) propertyInfo.getSchemaComponent()).getTerm()).getAnnotation() )){ - description = ((BindInfo)(((ParticleImpl) propertyInfo.getSchemaComponent()).getTerm()).getAnnotation().getAnnotation()).getDocumentation(); + else if (schemaComponent instanceof ParticleImpl){ + annotation = ((ParticleImpl)schemaComponent).getTerm().getAnnotation(); + } + return resolveDescription(annotation); + } + + /** + * Annotation (as well as documentation inside it) is optional in XSD, so both may be absent. + */ + static private String resolveDescription(XSAnnotation annotation){ + if (null == annotation || null == annotation.getAnnotation()){ + return ""; } - return description.trim(); + String description = ((BindInfo)annotation.getAnnotation()).getDocumentation(); + return null == description ? "" : description.trim(); } // @Override diff --git a/src/test/groovy/info/hubbitus/XJCPluginDescriptionAnnotationTest.groovy b/src/test/groovy/info/hubbitus/XJCPluginDescriptionAnnotationTest.groovy index 8321e9f..05c0ec7 100644 --- a/src/test/groovy/info/hubbitus/XJCPluginDescriptionAnnotationTest.groovy +++ b/src/test/groovy/info/hubbitus/XJCPluginDescriptionAnnotationTest.groovy @@ -110,4 +110,50 @@ class XJCPluginDescriptionAnnotationTest extends Specification { cls.getDeclaredFields().find{ 'name' == it.name }.getAnnotation(XsdInfo).name() == 'Фамилия и имя' cls.getDeclaredFields().find{ 'age' == it.name }.getAnnotation(XsdInfo).name() == 'Возраст' } + + /** + * https://github.com/Hubbitus/xjc-documentation-annotation-plugin/issues/2 + */ + def "XSD without documentation (or without annotation) must not cause NPE"(){ + setup: + File generatedClassesDir = new File(this.getClass().getResource('/').getPath() + 'generated-classes-nodoc') + generatedClassesDir.mkdir() + when: + int res = Driver.run( + [ + '-npa' + ,'-no-header' + ,'-XPluginDescriptionAnnotation' + ,'-d', generatedClassesDir.absolutePath + ,'-p', 'info.hubbitus.generated.nodoc' + ,this.getClass().getResource('/NoDocumentation.xsd') + ] as String[] + ,new XJCListener() { + @Override void error(SAXParseException e) { throw new IllegalStateException(e) } + @Override void fatalError(SAXParseException e) { throw new IllegalStateException(e) } + @Override void warning(SAXParseException e) { log.warn("SAX Parse warning: ", e) } + @Override void info(SAXParseException e) { log.info("SAX Parse information: ", e) } + } + ) + then: + res == 0 + + when: + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler() + int compileRes = compiler.run(null, null, null, + new File(generatedClassesDir, '/info/hubbitus/generated/nodoc/NoDoc.java').absolutePath, + new File(generatedClassesDir, '/info/hubbitus/generated/nodoc/NoAnnotation.java').absolutePath + ) + ClassLoader cl = new URLClassLoader([generatedClassesDir.toURI().toURL()] as URL[]) + Class noDoc = cl.loadClass('info.hubbitus.generated.nodoc.NoDoc') + Class noAnnotation = cl.loadClass('info.hubbitus.generated.nodoc.NoAnnotation') + then: + compileRes == 0 + noDoc.getDeclaredAnnotation(XsdInfo).name() == '' + noDoc.getDeclaredFields().find{ 'withoutAnnotation' == it.name }.getAnnotation(XsdInfo).name() == '' + noDoc.getDeclaredFields().find{ 'onlyAppinfo' == it.name }.getAnnotation(XsdInfo).name() == '' + noDoc.getDeclaredFields().find{ 'attrOnlyAppinfo' == it.name }.getAnnotation(XsdInfo).name() == '' + noDoc.getDeclaredFields().find{ 'attrWithoutAnnotation' == it.name }.getAnnotation(XsdInfo).name() == '' + noAnnotation.getDeclaredAnnotation(XsdInfo).name() == '' + } } diff --git a/src/test/resources/NoDocumentation.xsd b/src/test/resources/NoDocumentation.xsd new file mode 100644 index 0000000..09dfacc --- /dev/null +++ b/src/test/resources/NoDocumentation.xsd @@ -0,0 +1,31 @@ + + + + + + + Some application info + + + + + + Some application info + + + + + + Some application info + + + + + + + + + + + +