From fd0d53851124bd0afeb1ccdcc48c6822b5e3f769 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Fri, 13 Oct 2017 14:08:17 +0100 Subject: [PATCH] On JDK 9 call java.net.Authenticator.getDefault JDK 9 complains when java.lang.reflect.Field#setAccessible is called. So on JDK 9 to get the default Authenticator on JDK you can just call Authenticator.getDefault(). However lm targets JDK 8.. So on JDK 8 we do what we've always done, and on JDK 9 we use java reflection to call Authenticator.getDefault(), which is public and doesn't require setAccessible(true). Fixes #169 --- .../ivyint/ErrorMessageAuthenticator.scala | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/ErrorMessageAuthenticator.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/ErrorMessageAuthenticator.scala index 78e1154dc..1e842c458 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/ErrorMessageAuthenticator.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/ErrorMessageAuthenticator.scala @@ -1,6 +1,7 @@ package sbt.internal.librarymanagement package ivyint +import java.lang.reflect.InvocationTargetException import java.net.{ Authenticator, PasswordAuthentication } import org.apache.ivy.util.Message @@ -14,18 +15,41 @@ object ErrorMessageAuthenticator { private var securityWarningLogged = false private def originalAuthenticator: Option[Authenticator] = { - try { + if (isJavaVersion9Plus) getDefaultAuthenticator else getTheAuthenticator + } + + private[this] def getTheAuthenticator: Option[Authenticator] = { + withJavaReflectErrorHandling { val field = classOf[Authenticator].getDeclaredField("theAuthenticator") field.setAccessible(true) Option(field.get(null).asInstanceOf[Authenticator]) - } catch { - // TODO - Catch more specific errors. - case t: Throwable => - Message.debug("Error occurred while getting the original authenticator: " + t.getMessage) - None } } + private[this] def getDefaultAuthenticator: Option[Authenticator] = + withJavaReflectErrorHandling { + val method = classOf[Authenticator].getDeclaredMethod("getDefault") + Option(method.invoke(null).asInstanceOf[Authenticator]) + } + + private[this] def withJavaReflectErrorHandling[A](t: => Option[A]): Option[A] = { + try t + catch { + case e: ReflectiveOperationException => handleReflectionException(e) + case e: SecurityException => handleReflectionException(e) + case e: InvocationTargetException => handleReflectionException(e) + case e: ExceptionInInitializerError => handleReflectionException(e) + case e: IllegalArgumentException => handleReflectionException(e) + case e: NullPointerException => handleReflectionException(e) + case e: ClassCastException => handleReflectionException(e) + } + } + + private[this] def handleReflectionException(t: Throwable) = { + Message.debug("Error occurred while getting the original authenticator: " + t.getMessage) + None + } + private lazy val ivyOriginalField = { val field = classOf[IvyAuthenticator].getDeclaredField("original") field.setAccessible(true) @@ -76,6 +100,15 @@ object ErrorMessageAuthenticator { } doInstallIfIvy(originalAuthenticator) } + + private[this] def isJavaVersion9Plus = javaVersion > 8 + private[this] def javaVersion = { + // See Oracle section 1.5.3 at: + // https://docs.oracle.com/javase/8/docs/technotes/guides/versioning/spec/versioning2.html + val version = sys.props("java.specification.version").split("\\.").map(_.toInt) + if (version(0) == 1) version(1) else version(0) + } + } /**