diff --git a/build.gradle b/build.gradle index 63356da..ec16738 100644 --- a/build.gradle +++ b/build.gradle @@ -24,3 +24,6 @@ subprojects { configure(subprojects.findAll { it.name.startsWith('testdata')}) { tasks.findByPath("artifactoryPublish")?.enabled = false } +task wrapper(type: Wrapper) { + gradleVersion = '3.4.1' +} diff --git a/gradle.properties b/gradle.properties index edb6f43..353f142 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=1.2.6.RELEASE +version=1.2.9.BUILD-SNAPSHOT diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index b979729..efa0965 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 819f739..702d0d8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Sep 03 18:56:14 CEST 2013 +#Tue Mar 21 14:51:43 PDT 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-bin.zip diff --git a/gradlew b/gradlew index 91a7e26..4453cce 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,12 +6,30 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# 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 +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="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,31 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# 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 -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -90,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +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 @@ -114,6 +113,7 @@ fi 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` @@ -154,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +# 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")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 8a0b282..e95643d 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,90 +1,84 @@ -@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 - -@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= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@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 Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_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=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -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 +@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 diff --git a/springloaded/build.gradle b/springloaded/build.gradle index 73490ae..8a2402f 100644 --- a/springloaded/build.gradle +++ b/springloaded/build.gradle @@ -35,7 +35,7 @@ configurations { } task wrapper(type: Wrapper) { - gradleVersion = '1.8' + gradleVersion = '3.4.1' } dependencies { diff --git a/springloaded/gradle/wrapper/gradle-wrapper.jar b/springloaded/gradle/wrapper/gradle-wrapper.jar index 667288a..efa0965 100644 Binary files a/springloaded/gradle/wrapper/gradle-wrapper.jar and b/springloaded/gradle/wrapper/gradle-wrapper.jar differ diff --git a/springloaded/gradle/wrapper/gradle-wrapper.properties b/springloaded/gradle/wrapper/gradle-wrapper.properties index f0031c8..702d0d8 100644 --- a/springloaded/gradle/wrapper/gradle-wrapper.properties +++ b/springloaded/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Oct 15 14:09:30 PDT 2013 +#Tue Mar 21 14:51:43 PDT 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-bin.zip diff --git a/springloaded/gradlew b/springloaded/gradlew index 91a7e26..4453cce 100755 --- a/springloaded/gradlew +++ b/springloaded/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,12 +6,30 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# 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 +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="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,31 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# 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 -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -90,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +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 @@ -114,6 +113,7 @@ fi 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` @@ -154,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +# 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")" +fi + +exec "$JAVACMD" "$@" diff --git a/springloaded/gradlew.bat b/springloaded/gradlew.bat index 8a0b282..e95643d 100644 --- a/springloaded/gradlew.bat +++ b/springloaded/gradlew.bat @@ -1,90 +1,84 @@ -@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 - -@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= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@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 Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_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=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -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 +@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 diff --git a/springloaded/src/main/java/org/springsource/loaded/MethodInvokerRewriter.java b/springloaded/src/main/java/org/springsource/loaded/MethodInvokerRewriter.java index 71d66b9..8f8eb62 100644 --- a/springloaded/src/main/java/org/springsource/loaded/MethodInvokerRewriter.java +++ b/springloaded/src/main/java/org/springsource/loaded/MethodInvokerRewriter.java @@ -1045,6 +1045,11 @@ public class MethodInvokerRewriter { throw new IllegalStateException("Unable to find classId for " + slashedclassname + " referenced from invokedynamic in " + this.methodname + "()"); } + if(typeRegistry.getReloadableType(classId) == null) { + // can't rewrite non-reloading type + super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); + return; + } // Initially only rewriting use of INVOKEDYNAMIC to support Lambda execution // TODO support the more general invokedynamic usage diff --git a/springloaded/src/main/java/org/springsource/loaded/ReloadableType.java b/springloaded/src/main/java/org/springsource/loaded/ReloadableType.java index d0fea4d..6aa8ba2 100644 --- a/springloaded/src/main/java/org/springsource/loaded/ReloadableType.java +++ b/springloaded/src/main/java/org/springsource/loaded/ReloadableType.java @@ -166,8 +166,9 @@ public class ReloadableType { this.typeRegistry = typeRegistry; this.dottedtypename = dottedtypename; this.slashedtypename = dottedtypename.replace('.', '/'); - this.typedescriptor = (typeDescriptor != null ? typeDescriptor : typeRegistry.getExtractor().extract( - initialBytes, true)); + this.typedescriptor = (typeDescriptor != null ? typeDescriptor + : typeRegistry.getExtractor().extract( + initialBytes, true)); this.interfaceBytes = InterfaceExtractor.extract(initialBytes, typeRegistry, this.typedescriptor); this.bytesInitial = initialBytes; rewriteCallSitesAndDefine(); @@ -544,12 +545,17 @@ public class ReloadableType { private void reloadProxiesIfNecessary(String versionsuffix) { ReloadableType proxy = typeRegistry.cglibProxies.get(this.slashedtypename); if (proxy != null) { + if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) { + log.log(Level.INFO, "Attempting reload of cglib proxy for type " + this.slashedtypename); + } + Object[] strategyAndGeneratorPair = CglibPluginCapturing.clazzToGeneratorStrategyAndClassGeneratorMap.get( getClazz()); if (strategyAndGeneratorPair == null) { if (log.isLoggable(Level.SEVERE)) { log.severe( - "Unable to find regeneration methods for cglib proxies - proxies will be out of date for this type"); + "Unable to find regeneration methods for cglib proxies - proxies will be out of date for type: " + + getClazz()); } return; } @@ -567,6 +573,9 @@ public class ReloadableType { } found.setAccessible(true); byte[] bs = (byte[]) found.invoke(a, b); + if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) { + log.log(Level.INFO, "Proxy regenerate successful for " + this.slashedtypename); + } proxy.loadNewVersion(versionsuffix, bs); proxy.runStaticInitializer(); } @@ -596,6 +605,9 @@ public class ReloadableType { } } byte[] bs = (byte[]) found.invoke(a, b); + if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) { + log.log(Level.INFO, "Proxy (fastclass) regenerate successful for " + this.slashedtypename); + } proxy.loadNewVersion(versionsuffix, bs); proxy.runStaticInitializer(); } @@ -612,10 +624,8 @@ public class ReloadableType { if (relevantProxies != null) { for (ReloadableType relevantProxy : relevantProxies) { Class[] interfacesImplementedByProxy = relevantProxy.getClazz().getInterfaces(); - // check slashedname correct - // @SuppressWarnings("restriction") - byte[] newProxyBytes = sun.misc.ProxyGenerator.generateProxyClass( - relevantProxy.getSlashedName(), + // TODO confirm slashedname correct + byte[] newProxyBytes = Utils.generateProxyClass(relevantProxy.getSlashedName(), interfacesImplementedByProxy); relevantProxy.loadNewVersion(versionsuffix, newProxyBytes, true); } diff --git a/springloaded/src/main/java/org/springsource/loaded/Utils.java b/springloaded/src/main/java/org/springsource/loaded/Utils.java index a79c0e5..22ed787 100644 --- a/springloaded/src/main/java/org/springsource/loaded/Utils.java +++ b/springloaded/src/main/java/org/springsource/loaded/Utils.java @@ -44,6 +44,7 @@ import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.FieldNode; import org.springsource.loaded.Utils.ReturnType.Kind; +import sun.misc.ProxyGenerator; // TODO debugging tests - how is the experience? rewriting of field accesses will really // affect field navigation in the debugger @@ -1935,4 +1936,38 @@ public class Utils implements Opcodes, Constants { cr.accept(v, 0); return v.classname; } + + private static boolean checkedForNewProxyGenerateMethod = false; + + private static Method newProxyGenerateMethod; + + public static byte[] generateProxyClass(String slashedName, Class[] interfacesImplementedByProxy) { + if (!checkedForNewProxyGenerateMethod) { + checkedForNewProxyGenerateMethod = true; + try { + newProxyGenerateMethod = ProxyGenerator.class.getDeclaredMethod("generateProxyClass", String.class, + Class[].class, Integer.TYPE); + } + catch (NoSuchMethodException nsme) { + // That's fine, we are early Java8 or before + } + } + if (newProxyGenerateMethod != null) { + try { + newProxyGenerateMethod.setAccessible(true); + byte[] bytes = (byte[]) newProxyGenerateMethod.invoke(null, slashedName, interfacesImplementedByProxy, + (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL)); + return bytes; + } + catch (Exception e) { + // Unexpected + throw new RuntimeException("Unexpected exception calling proxy generator ", e); + } + } + else { + return sun.misc.ProxyGenerator.generateProxyClass( + slashedName, + interfacesImplementedByProxy); + } + } } diff --git a/springloaded/src/main/java/org/springsource/loaded/agent/CglibPluginCapturing.java b/springloaded/src/main/java/org/springsource/loaded/agent/CglibPluginCapturing.java index 41611c3..a0dac3b 100644 --- a/springloaded/src/main/java/org/springsource/loaded/agent/CglibPluginCapturing.java +++ b/springloaded/src/main/java/org/springsource/loaded/agent/CglibPluginCapturing.java @@ -19,23 +19,28 @@ package org.springsource.loaded.agent; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.springsource.loaded.Constants; +import org.springsource.loaded.GlobalConfiguration; /** * This bytecode rewriter intercepts calls to generate made in the CGLIB framework and allows us to record what * generator is called to create the proxy for some type. The same generator can then be driven again if the type is * reloaded. - * + * * @author Andy Clement * @since 0.8.3 */ public class CglibPluginCapturing extends ClassVisitor implements Constants { + private static Logger log = Logger.getLogger(CglibPluginCapturing.class.getName()); + public static Map, Object[]> clazzToGeneratorStrategyAndClassGeneratorMap = new HashMap, Object[]>(); public static Map, Object[]> clazzToGeneratorStrategyAndFastClassGeneratorMap = new HashMap, Object[]>(); @@ -68,11 +73,22 @@ public class CglibPluginCapturing extends ClassVisitor implements Constants { return ((ClassWriter) cv).toByteArray(); } + @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { if (name.equals("create")) { + if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) { + log.info("intercepting create method"); + } MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); return new CreateMethodInterceptor(mv); } + else if (name.equals("generate")) { + if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) { + log.info("intercepting generate method"); + } + MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); + return new GenerateMethodInterceptor(mv); + } else { return super.visitMethod(access, name, desc, signature, exceptions); } @@ -98,6 +114,9 @@ public class CglibPluginCapturing extends ClassVisitor implements Constants { final boolean itf) { super.visitMethodInsn(opcode, owner, name, desc, itf); if (name.equals("generate")) { + if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) { + log.info("intercepting call to generate in create method"); + } // Code that calls generate: // ALOAD 0 // GETFIELD net/sf/cglib/core/AbstractClassGenerator.strategy : Lnet/sf/cglib/core/GeneratorStrategy; @@ -108,22 +127,46 @@ public class CglibPluginCapturing extends ClassVisitor implements Constants { "L" + prefix + "/cglib/core/GeneratorStrategy;"); mv.visitVarInsn(ALOAD, 0); // AbstractClassGenerator instance mv.visitMethodInsn(INVOKESTATIC, "org/springsource/loaded/agent/CglibPluginCapturing", "record", - "(Ljava/lang/Object;Ljava/lang/Object;)V", false);//Lnet/sf/cglib/core/GeneratorStrategy;Lnet/sf/cglib/core/AbstractClassGenerator);"); + "(Ljava/lang/Object;Ljava/lang/Object;)V", false);//Lnet/sf/cglib/core/GeneratorStrategy;Lnet/sf/cglib/core/AbstractClassGenerator);"); } } } + + class GenerateMethodInterceptor extends MethodVisitor implements Constants { + + public GenerateMethodInterceptor(MethodVisitor mv) { + super(ASM5, mv); + } + + @Override + public void visitCode() { + mv.visitVarInsn(ALOAD, 0); // AbstractClassGenerator instance + mv.visitFieldInsn(GETFIELD, prefix + "/cglib/core/AbstractClassGenerator", "strategy", + "L" + prefix + "/cglib/core/GeneratorStrategy;"); + mv.visitVarInsn(ALOAD, 0); // AbstractClassGenerator instance + mv.visitMethodInsn(INVOKESTATIC, "org/springsource/loaded/agent/CglibPluginCapturing", "record", + "(Ljava/lang/Object;Ljava/lang/Object;)V", false);//Lnet/sf/cglib/core/GeneratorStrategy;Lnet/sf/cglib/core/AbstractClassGenerator);"); + + } + + } + /** * The classloader for class artifacts is used to load the generated classes for call sites. We need to rewrite * these classes because they may be either calling something that disappears on a later reload (so need to fail * appropriately) or calling something that isnt there on the first load - in this latter case they are changed to * route the dynamic executor method. - * + * * @param a the GeneratorStrategy being used * @param b the AbstractClassGenerator */ public static void record(Object a, Object b) { + // if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) { + // log.info("recording invocation of generate with " + (a == null ? "null" : a.getClass().getName()) + " b=" + // + (b == null ? "null" : b.getClass().getName())); + // } // a is a Lnet/sf/cglib/core/GeneratorStrategy; // b is a Lnet/sf/cglib/core/AbstractClassGenerator (or specifically net/sf/cglib/reflect/FastClass$Generator) // a is something like 'UndeclaredThrowableStrategy' @@ -134,7 +177,9 @@ public class CglibPluginCapturing extends ClassVisitor implements Constants { Field f = b.getClass().getDeclaredField("superclass"); f.setAccessible(true); Class clazz = (Class) f.get(b); - // System.out.println("Recording pair " + clazz.getName() + " > " + b); + if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) { + log.info("recording pair " + clazz.getName() + " > " + b); + } clazzToGeneratorStrategyAndClassGeneratorMap.put(clazz, new Object[] { a, b }); } catch (Throwable re) { @@ -146,7 +191,9 @@ public class CglibPluginCapturing extends ClassVisitor implements Constants { Field f = b.getClass().getDeclaredField("type"); f.setAccessible(true); Class clazz = (Class) f.get(b); - // System.out.println("Recording pair (fastclass) " + clazz.getName() + " > " + b); + if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) { + log.info("recording pair (fastclass) " + clazz.getName() + " > " + b); + } clazzToGeneratorStrategyAndFastClassGeneratorMap.put(clazz, new Object[] { a, b }); } catch (Throwable re) { diff --git a/springloaded/src/main/java/org/springsource/loaded/agent/SpringPlugin.java b/springloaded/src/main/java/org/springsource/loaded/agent/SpringPlugin.java index 4b0d7bf..19840c3 100644 --- a/springloaded/src/main/java/org/springsource/loaded/agent/SpringPlugin.java +++ b/springloaded/src/main/java/org/springsource/loaded/agent/SpringPlugin.java @@ -110,8 +110,8 @@ public class SpringPlugin implements LoadtimeInstrumentationPlugin, ReloadEventP public byte[] modify(String slashedClassName, ClassLoader classLoader, byte[] bytes) { - if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) { - log.info("loadtime modifying " + slashedClassName); + if ((GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) || debug) { + log.info("SPRING_PLUGIN: loadtime modifying " + slashedClassName); } if (slashedClassName.equals("org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter")) { return bytesWithInstanceCreationCaptured(bytes, THIS_CLASS, @@ -140,6 +140,9 @@ public class SpringPlugin implements LoadtimeInstrumentationPlugin, ReloadEventP } public static void recordRequestMappingHandlerMappingInstance(Object obj) { + if (debug) { + System.out.println("SPRING_PLUGIN: Recording request mapping handler mapping instance..." + obj); + } requestMappingHandlerMappingInstances.add(obj); } @@ -163,7 +166,7 @@ public class SpringPlugin implements LoadtimeInstrumentationPlugin, ReloadEventP // called by the modified code public static void recordDefaultAnnotationHandlerMappingInstance(Object obj) { if (debug) { - System.out.println("Recording new instance of DefaultAnnotationHandlerMappingInstance"); + System.out.println("SPRING_PLUGIN: Recording new instance of DefaultAnnotationHandlerMappingInstance"); } defaultAnnotationHandlerMappingInstances.add(obj); } @@ -188,7 +191,7 @@ public class SpringPlugin implements LoadtimeInstrumentationPlugin, ReloadEventP return; } if (debug) { - System.out.println("ParameterNamesCache: Clearing parameter name discoverer caches"); + System.out.println("SPRING_PLUGIN: ParameterNamesCache: Clearing parameter name discoverer caches"); } if (parameterNamesCacheField == null) { try { @@ -207,7 +210,8 @@ public class SpringPlugin implements LoadtimeInstrumentationPlugin, ReloadEventP Object o = parameterNamesCache.remove(clazz); if (debug) { System.out.println( - "ParameterNamesCache: Removed " + clazz.getName() + " from cache?" + (o != null)); + "SPRING_PLUGIN: ParameterNamesCache: Removed " + clazz.getName() + " from cache?" + + (o != null)); } } catch (IllegalAccessException e) { @@ -230,7 +234,7 @@ public class SpringPlugin implements LoadtimeInstrumentationPlugin, ReloadEventP Method removeMethod = Map.class.getDeclaredMethod("remove", Object.class); Object ret = removeMethod.invoke(map, clazz); if (GlobalConfiguration.debugplugins) { - System.err.println("SpringPlugin: clearing methodResolverCache for " + clazz.getName()); + System.err.println("SPRING_PLUGIN: clearing methodResolverCache for " + clazz.getName()); } if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.INFO)) { log.info("cleared a cache entry? " + (ret != null)); @@ -342,7 +346,8 @@ public class SpringPlugin implements LoadtimeInstrumentationPlugin, ReloadEventP // protected void detectHandlers() throws BeansException { is defined on AbstractDetectingUrlHandlerMapping for (Object o : defaultAnnotationHandlerMappingInstances) { if (debug) { - System.out.println("Invoking detectHandlers on instance of DefaultAnnotationHandlerMappingInstance"); + System.out.println( + "SPRING_PLUGIN: Invoking detectHandlers on instance of DefaultAnnotationHandlerMappingInstance"); } try { Class clazz_AbstractDetectingUrlHandlerMapping = o.getClass().getSuperclass(); @@ -360,50 +365,140 @@ public class SpringPlugin implements LoadtimeInstrumentationPlugin, ReloadEventP } } - @SuppressWarnings("rawtypes") private void reinvokeInitHandlerMethods() { // org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping (super AbstractHandlerMethodMapping) - call protected void initHandlerMethods() on it. - for (Object o : requestMappingHandlerMappingInstances) { if (debug) { - System.out.println("Invoking initHandlerMethods on instance of RequestMappingHandlerMapping"); + System.out.println( + "SPRING_PLUGIN: Invoking initHandlerMethods on instance of RequestMappingHandlerMapping"); } + Class clazz_AbstractHandlerMethodMapping = null; try { - Class clazz_AbstractHandlerMethodMapping = o.getClass().getSuperclass().getSuperclass(); - - // private final Map handlerMethods = new LinkedHashMap(); - Field field_handlerMethods = clazz_AbstractHandlerMethodMapping.getDeclaredField("handlerMethods"); - field_handlerMethods.setAccessible(true); - Map m = (Map) field_handlerMethods.get(o); - m.clear(); - - Field field_urlMap = clazz_AbstractHandlerMethodMapping.getDeclaredField("urlMap"); - field_urlMap.setAccessible(true); - m = (Map) field_urlMap.get(o); - m.clear(); - - Method method_initHandlerMethods = clazz_AbstractHandlerMethodMapping.getDeclaredMethod( - "initHandlerMethods"); - method_initHandlerMethods.setAccessible(true); - method_initHandlerMethods.invoke(o); - } - catch (NoSuchFieldException nsfe) { - if (debug) { - if (nsfe.getMessage().equals("handlerMethods")) { - System.out.println( - "problem resetting request mapping handlers - unable to find field 'handlerMethods' on type 'AbstractHandlerMethodMapping' - you probably are not on Spring 3.1"); - } - else { - System.out.println("problem resetting request mapping handlers - NoSuchFieldException: " - + nsfe.getMessage()); - } - } + clazz_AbstractHandlerMethodMapping = o.getClass().getSuperclass().getSuperclass(); } catch (Exception e) { + if (debug) { + System.out.println("SPRING_PLUGIN: Unable to get to AbstractHandlerMethodMapping from RMHM"); + } if (GlobalConfiguration.debugplugins) { e.printStackTrace(); } } + + if (clazz_AbstractHandlerMethodMapping != null) { + try { + // private final Map handlerMethods = new LinkedHashMap(); + Field field_handlerMethods = clazz_AbstractHandlerMethodMapping.getDeclaredField("handlerMethods"); + field_handlerMethods.setAccessible(true); + Map m = (Map) field_handlerMethods.get(o); + m.clear(); + } + catch (NoSuchFieldException e) { + if (debug) { + System.out.println("SPRING_PLUGIN: Unable to find handlerMethods field to clear"); + } + } + catch (Exception e) { + if (GlobalConfiguration.debugplugins) { + e.printStackTrace(); + } + } + + try { + Field field_urlMap = clazz_AbstractHandlerMethodMapping.getDeclaredField("urlMap"); + field_urlMap.setAccessible(true); + Map m = (Map) field_urlMap.get(o); + m.clear(); + } + catch (NoSuchFieldException e) { + if (debug) { + System.out.println("SPRING_PLUGIN: Unable to find urlMap field to clear"); + } + } + catch (Exception e) { + if (GlobalConfiguration.debugplugins) { + e.printStackTrace(); + } + } + clearMappingRegistry(o, clazz_AbstractHandlerMethodMapping); + + + try { + + Method method_initHandlerMethods = clazz_AbstractHandlerMethodMapping.getDeclaredMethod( + "initHandlerMethods"); + method_initHandlerMethods.setAccessible(true); + method_initHandlerMethods.invoke(o); + } + catch (Exception e) { + if (GlobalConfiguration.debugplugins || debug) { + e.printStackTrace(); + } + } + } + + } + + } + + + // More recent Springs use a MappingRegistry - clear it out if we can get at it, otherwise on re-driving + // the initHandlerMethods below we will get an error about already existing mappings + private void clearMappingRegistry(Object o, Class clazz_AbstractHandlerMethodMapping) { + if (debug) { + System.out.println("SPRING_PLUGIN: clearing out mapping registry..."); + } + Object mappingRegistryInstance = null; + try { + Field field_mappingRegistry = clazz_AbstractHandlerMethodMapping.getDeclaredField("mappingRegistry"); + field_mappingRegistry.setAccessible(true); + mappingRegistryInstance = field_mappingRegistry.get(o); + } + catch (NoSuchFieldException e) { + if (debug) { + System.out.println( + "SPRING_PLUGIN: Unable to get mappingRegistry field on AbstractHandlerMethodMapping"); + } + } + catch (IllegalAccessException e) { + if (GlobalConfiguration.debugplugins || debug) { + System.out.println( + "SPRING_PLUGIN: Problem accessing mappingRegistry field on AbstractHandlerMethodMapping: "); + e.printStackTrace(System.out); + } + } + + if (mappingRegistryInstance == null) { + return; + } + Class mappingRegistryClass = mappingRegistryInstance.getClass(); + + clearMapField(mappingRegistryClass, mappingRegistryInstance, "registry"); + clearMapField(mappingRegistryClass, mappingRegistryInstance, "mappingLookup"); + clearMapField(mappingRegistryClass, mappingRegistryInstance, "urlLookup"); + clearMapField(mappingRegistryClass, mappingRegistryInstance, "nameLookup"); + clearMapField(mappingRegistryClass, mappingRegistryInstance, "corsLookup"); + if (debug) { + System.out.println("SPRING_PLUGIN: ... cleared out the mapping registry contents"); + } + } + + private void clearMapField(Class clazz, Object instance, String name) { + try { + Field field = clazz.getDeclaredField(name); + field.setAccessible(true); + Map m = (Map) field.get(instance); + m.clear(); + } + catch (NoSuchFieldException e) { + if (debug) { + System.out.println("SPRING_PLUGIN: Unable to find field '" + name + "' to clear"); + } + } + catch (Exception e) { + if (GlobalConfiguration.debugplugins || debug) { + e.printStackTrace(); + } } } diff --git a/springloaded/src/main/java/org/springsource/loaded/ri/ReflectiveInterceptor.java b/springloaded/src/main/java/org/springsource/loaded/ri/ReflectiveInterceptor.java index dc06ff1..28d8fd7 100644 --- a/springloaded/src/main/java/org/springsource/loaded/ri/ReflectiveInterceptor.java +++ b/springloaded/src/main/java/org/springsource/loaded/ri/ReflectiveInterceptor.java @@ -53,7 +53,7 @@ import org.springsource.loaded.TypeRegistry; import org.springsource.loaded.Utils; import org.springsource.loaded.infra.UsedByGeneratedCode; import org.springsource.loaded.jvm.JVM; - +import org.springsource.loaded.support.ConcurrentWeakIdentityHashMap; /** * The reflective interceptor is called to rewrite any reflective calls that are found in the bytecode. Intercepting the @@ -84,7 +84,8 @@ public class ReflectiveInterceptor { classToRType = Collections.synchronizedMap(new WeakHashMap, WeakReference>()); } else { - classToRType = new WeakHashMap, WeakReference>(); + classToRType = new ConcurrentWeakIdentityHashMap, WeakReference>(); + // classToRType = new WeakHashMap, WeakReference>(); } } @@ -650,7 +651,7 @@ public class ReflectiveInterceptor { */ private static Field asSetableField(Field field, Object target, Class valueType, Object value, boolean makeAccessibleCopy) - throws IllegalAccessException { + throws IllegalAccessException { // Must do the checks exactly in the same order as JVM if we want identical error messages. // JVM doesn't do this, since it cannot happen without reloading, we do it first of all. @@ -1054,7 +1055,7 @@ public class ReflectiveInterceptor { c = jlClassGetDeclaredConstructor(clazz); } catch (NoSuchMethodException e) { - e.printStackTrace(); + // e.printStackTrace(); throw Exceptions.instantiation(clazz); } c = asAccessibleConstructor(c, true); diff --git a/springloaded/src/main/java/org/springsource/loaded/support/ConcurrentWeakIdentityHashMap.java b/springloaded/src/main/java/org/springsource/loaded/support/ConcurrentWeakIdentityHashMap.java new file mode 100644 index 0000000..0b98744 --- /dev/null +++ b/springloaded/src/main/java/org/springsource/loaded/support/ConcurrentWeakIdentityHashMap.java @@ -0,0 +1,271 @@ +/* + * Copyright 2016 zhanhb. + * + * 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 org.springsource.loaded.support; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.lang.NullPointerException; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * + * @author zhanhb + * @param + * @param + */ +public class ConcurrentWeakIdentityHashMap extends AbstractMap + implements ConcurrentMap { + + private final ConcurrentMap, V> map; + private final ReferenceQueue queue = new ReferenceQueue(); + private transient Set> es; + + public ConcurrentWeakIdentityHashMap(int initialCapacity) { + this.map = new ConcurrentHashMap, V>(initialCapacity); + } + + @SuppressWarnings("CollectionWithoutInitialCapacity") + public ConcurrentWeakIdentityHashMap() { + this.map = new ConcurrentHashMap, V>(); + } + + @Override + public V get(Object key) { + purgeKeys(); + return map.get(new Key(key, null)); + } + + @Override + public V put(K key, V value) { + purgeKeys(); + return map.put(new Key(key, queue), value); + } + + @Override + public int size() { + purgeKeys(); + return map.size(); + } + + @SuppressWarnings({"NestedAssignment", "element-type-mismatch"}) + private void purgeKeys() { + Reference reference; + while ((reference = queue.poll()) != null) { + map.remove(reference); + } + } + + @Override + @SuppressWarnings("NestedAssignment") + public Set> entrySet() { + Set> entrySet; + return ((entrySet = this.es) == null) ? es = new EntrySet() : entrySet; + } + + @Override + public V putIfAbsent(K key, V value) { + purgeKeys(); + return map.putIfAbsent(new Key(key, queue), value); + } + + @Override + public V remove(Object key) { + return map.remove(new Key(key, null)); + } + + @Override + public boolean remove(Object key, Object value) { + purgeKeys(); + return map.remove(new Key(key, null), value); + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + purgeKeys(); + return map.replace(new Key(key, null), oldValue, newValue); + } + + @Override + public V replace(K key, V value) { + purgeKeys(); + return map.replace(new Key(key, null), value); + } + + @Override + public boolean containsKey(Object key) { + purgeKeys(); + return map.containsKey(new Key(key, null)); + } + + @Override + @SuppressWarnings("empty-statement") + public void clear() { + while (queue.poll() != null); + map.clear(); + } + + @Override + public boolean containsValue(Object value) { + purgeKeys(); + return map.containsValue(value); + } + + private static class Key extends WeakReference { + + private final int hash; + + Key(T t, ReferenceQueue queue) { + super(t, queue); + if(t == null) { + throw new NullPointerException(); + } else { + hash = System.identityHashCode(t); + } + } + + @Override + public boolean equals(Object obj) { + return this == obj || obj instanceof Key && ((Key) obj).get() == get(); + } + + @Override + public int hashCode() { + return hash; + } + + } + + private class Iter implements Iterator> { + + private final Iterator, V>> it; + private Map.Entry nextValue; + + Iter(Iterator, V>> it) { + this.it = it; + } + + @Override + public boolean hasNext() { + if (nextValue != null) { + return true; + } + while (it.hasNext()) { + Map.Entry, V> entry = it.next(); + K key = entry.getKey().get(); + if (key != null) { + nextValue = new Entry(key, entry.getValue()); + return true; + } else { + it.remove(); + } + } + return false; + } + + @Override + public Map.Entry next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + Map.Entry entry = nextValue; + nextValue = null; + return entry; + } + + @Override + public void remove() { + it.remove(); + nextValue = null; + } + + } + + private class EntrySet extends AbstractSet> { + + @Override + public Iterator> iterator() { + return new Iter(map.entrySet().iterator()); + } + + @Override + public int size() { + return ConcurrentWeakIdentityHashMap.this.size(); + } + + @Override + public void clear() { + ConcurrentWeakIdentityHashMap.this.clear(); + } + + @Override + @SuppressWarnings("element-type-mismatch") + public boolean contains(Object o) { + if (!(o instanceof Map.Entry)) { + return false; + } + Map.Entry e = (Map.Entry) o; + return ConcurrentWeakIdentityHashMap.this.get(e.getKey()) == e.getValue(); + } + + @Override + public boolean remove(Object o) { + if (!(o instanceof Map.Entry)) { + return false; + } + Map.Entry e = (Map.Entry) o; + return ConcurrentWeakIdentityHashMap.this.remove(e.getKey(), e.getValue()); + } + } + + private class Entry extends AbstractMap.SimpleEntry { + + private static final long serialVersionUID = 1L; + + Entry(K key, V value) { + super(key, value); + } + + @Override + public V setValue(V value) { + ConcurrentWeakIdentityHashMap.this.put(getKey(), value); + return super.setValue(value); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Map.Entry) { + Map.Entry e = (Map.Entry) obj; + return getKey() == e.getKey() && getValue() == e.getValue(); + } + return false; + } + + @Override + public int hashCode() { + return System.identityHashCode(getKey()) + ^ System.identityHashCode(getValue()); + } + } + +} \ No newline at end of file diff --git a/springloaded/src/main/java/org/springsource/loaded/support/Java8.java b/springloaded/src/main/java/org/springsource/loaded/support/Java8.java index 7218e13..25f2432 100644 --- a/springloaded/src/main/java/org/springsource/loaded/support/Java8.java +++ b/springloaded/src/main/java/org/springsource/loaded/support/Java8.java @@ -150,8 +150,8 @@ public class Java8 { if (null == ownerRType || !ownerRType.hasBeenReloaded()) { // target containing the reference/lambdaMethod has not been reloaded, no need to get over // complicated. - Class ownerClazz = ownerRType.getClazz(); - implMethod = caller.findVirtual(ownerClazz, name, implMethodType); + Class clazz = callerLoader.loadClass(owner.replace("/", ".")); + implMethod = caller.findVirtual(clazz, name, implMethodType); } else { MethodMember targetReferenceMethodMember = ownerRType.getCurrentMethod(name, descriptor); diff --git a/springloaded/src/test/java/org/springsource/loaded/test/ConstantPoolScannerTests.java b/springloaded/src/test/java/org/springsource/loaded/test/ConstantPoolScannerTests.java index 0c55c10..1c32efe 100644 --- a/springloaded/src/test/java/org/springsource/loaded/test/ConstantPoolScannerTests.java +++ b/springloaded/src/test/java/org/springsource/loaded/test/ConstantPoolScannerTests.java @@ -23,6 +23,7 @@ import java.io.FileInputStream; import java.io.Serializable; import java.util.List; +import org.junit.Ignore; import org.junit.Test; import org.springsource.loaded.ConstantPoolScanner; import org.springsource.loaded.ConstantPoolScanner.References; @@ -55,6 +56,7 @@ public class ConstantPoolScannerTests { } + @Ignore @Test public void foo() throws Exception { diff --git a/springloaded/src/test/java/org/springsource/loaded/test/Java8Tests.java b/springloaded/src/test/java/org/springsource/loaded/test/Java8Tests.java index 665880e..8c7779e 100644 --- a/springloaded/src/test/java/org/springsource/loaded/test/Java8Tests.java +++ b/springloaded/src/test/java/org/springsource/loaded/test/Java8Tests.java @@ -68,6 +68,26 @@ public class Java8Tests extends SpringLoadedTests { // TODO should assert something but the issue is that the JVM crashes... } + @Test + public void issue173() throws Exception { + String t = "bugs.Issue173"; + TypeRegistry typeRegistry = getTypeRegistry(t); + byte[] sc = loadBytesForClass(t); + ReloadableType rtype = typeRegistry.addType(t, sc); + + Class clazz = rtype.getClazz(); + @SuppressWarnings("unused") + Result r = runUnguarded(clazz, "run"); + + r = runUnguarded(clazz, "run"); + + rtype.loadNewVersion("002", rtype.bytesInitial); + + r = runUnguarded(clazz, "run"); + + assertEquals("https://www.redacted.com/path", r.returnValue); + } + @Test public void callBasicType() throws Exception { String t = "basic.FirstClass"; diff --git a/testdata-java8/src/main/java/bugs/Issue173.java b/testdata-java8/src/main/java/bugs/Issue173.java new file mode 100644 index 0000000..324ac9f --- /dev/null +++ b/testdata-java8/src/main/java/bugs/Issue173.java @@ -0,0 +1,49 @@ +package bugs; + +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +public class Issue173 { + public static void main(String[] args) { + System.out.println(run()); + } + + public static String run() { + return url("path").toString(); + } + + public static URI url(Object... args) { + try { + /* flattening the paths */ + final List paths = Arrays + .stream(args) + .flatMap(arg -> { + if (arg instanceof Collection) { + return ((Collection) arg).stream(); + } else if (arg instanceof Object[]) { + return Arrays.stream((Object[]) arg); + } + + return Arrays.stream(new Object[]{ + arg + }); + }) + .map(Object::toString) + .map(String::toLowerCase) + .collect(Collectors.toList()); + + Path path = Paths.get("/", paths.toArray(new String[0])); + URI uri = new URI("https", "www.redacted.com", path.toString(), null); + + return uri; + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } +}