Skip to content

Commit

Permalink
ClassValueCompat to support systems without java.lang.ClassValue
Browse files Browse the repository at this point in the history
On runtime systems where `java.lang.ClassValue` is not available
`ClassValueCompat` re-computes the value on each `get` invocation.

Co-authored-by: nwk37011 <nwk37011@gmail.com>
  • Loading branch information
lrytz and nwk37011 committed Oct 12, 2021
1 parent 5a4e273 commit 6c9dd4d
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 56 deletions.
10 changes: 10 additions & 0 deletions project/MimaFilters.scala
Expand Up @@ -78,6 +78,16 @@ object MimaFilters extends AutoPlugin {

// #9741
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.SeqMap$SeqMapBuilderImpl"), // private[SeqMap]

// #9752
ProblemFilters.exclude[MissingTypesProblem]("scala.reflect.ClassTag$cache$"),
ProblemFilters.exclude[MissingClassProblem]("scala.runtime.ModuleSerializationProxy$"),
ProblemFilters.exclude[MissingTypesProblem]("scala.reflect.runtime.JavaMirrors$JavaMirror$typeTagCache$"),
ProblemFilters.exclude[MissingClassProblem]("scala.runtime.ClassValueCompat"),
ProblemFilters.exclude[MissingClassProblem]("scala.runtime.ClassValueCompat$"),
ProblemFilters.exclude[MissingClassProblem]("scala.runtime.ClassValueCompat$ClassValueInterface"),
ProblemFilters.exclude[MissingClassProblem]("scala.runtime.ClassValueCompat$JavaClassValue"),
ProblemFilters.exclude[MissingClassProblem]("scala.runtime.ClassValueCompat$FallbackClassValue"),
)

override val buildSettings = Seq(
Expand Down
4 changes: 2 additions & 2 deletions src/library/scala/reflect/ClassTag.scala
Expand Up @@ -15,8 +15,8 @@ package reflect

import java.lang.{Class => jClass}
import java.lang.ref.{WeakReference => jWeakReference}

import scala.annotation.{implicitNotFound, nowarn}
import scala.runtime.ClassValueCompat

/**
*
Expand Down Expand Up @@ -116,7 +116,7 @@ object ClassTag {
val Null : ClassTag[scala.Null] = Manifest.Null

private val cacheDisabled = java.lang.Boolean.getBoolean("scala.reflect.classtag.cache.disable")
private[this] object cache extends ClassValue[jWeakReference[ClassTag[_]]] {
private[this] object cache extends ClassValueCompat[jWeakReference[ClassTag[_]]] {
override def computeValue(runtimeClass: jClass[_]): jWeakReference[ClassTag[_]] =
new jWeakReference(computeTag(runtimeClass))

Expand Down
53 changes: 53 additions & 0 deletions src/library/scala/runtime/ClassValueCompat.scala
@@ -0,0 +1,53 @@
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/

package scala.runtime


import scala.runtime.ClassValueCompat._

private[scala] abstract class ClassValueCompat[T] extends ClassValueInterface[T] { self =>
private val instance: ClassValueInterface[T] =
if (classValueAvailable) new JavaClassValue()
else new FallbackClassValue()

private class JavaClassValue extends ClassValue[T] with ClassValueInterface[T] {
override def computeValue(cls: Class[_]): T = self.computeValue(cls)
}

private class FallbackClassValue extends ClassValueInterface[T] {
override def get(cls: Class[_]): T = self.computeValue(cls)

override def remove(cls: Class[_]): Unit = {}
}

def get(cls: Class[_]): T = instance.get(cls)

def remove(cls: Class[_]): Unit = instance.remove(cls)

protected def computeValue(cls: Class[_]): T
}

private[scala] object ClassValueCompat {
trait ClassValueInterface[T] {
def get(cls: Class[_]): T

def remove(cls: Class[_]): Unit
}

private val classValueAvailable: Boolean = try {
Class.forName("java.lang.ClassValue", false, classOf[Object].getClassLoader)
true
} catch {
case _: ClassNotFoundException => false
}
}
51 changes: 0 additions & 51 deletions src/library/scala/runtime/ModuleSerializationProxy.java

This file was deleted.

43 changes: 43 additions & 0 deletions src/library/scala/runtime/ModuleSerializationProxy.scala
@@ -0,0 +1,43 @@
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/

package scala.runtime

import java.io.Serializable
import java.security.PrivilegedActionException
import java.security.PrivilegedExceptionAction

private[runtime] object ModuleSerializationProxy {
private val instances = new ClassValueCompat[Object] {
override protected def computeValue(cls: Class[_]): Object = {
try {
java.security.AccessController.doPrivileged((() => cls.getField("MODULE$").get(null)): PrivilegedExceptionAction[Object])
} catch {
case e: PrivilegedActionException =>
rethrowRuntime(e.getCause)
}
}
}

private def rethrowRuntime(e: Throwable): Object = {
val cause = e.getCause
cause match {
case exception: RuntimeException => throw exception
case _ => throw new RuntimeException(cause)
}
}
}

@SerialVersionUID(1L)
final class ModuleSerializationProxy(moduleClass: Class[_]) extends Serializable {
private def readResolve = ModuleSerializationProxy.instances.get(moduleClass)
}
3 changes: 2 additions & 1 deletion src/reflect/scala/reflect/macros/Attachments.scala
Expand Up @@ -15,6 +15,7 @@ package reflect
package macros

import reflect.internal.util.Position
import scala.runtime.ClassValueCompat

/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
Expand Down Expand Up @@ -109,7 +110,7 @@ abstract class Attachments { self =>
}

private object Attachments {
private val matchesTagCache = new ClassValue[Function1[Any, Boolean]] {
private val matchesTagCache = new ClassValueCompat[Function1[Any, Boolean]] {
override def computeValue(cls: Class[_]): Function[Any, Boolean] = cls.isInstance(_)
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/reflect/scala/reflect/runtime/JavaMirrors.scala
Expand Up @@ -38,7 +38,7 @@ import internal.Flags._
import ReflectionUtils._
import scala.annotation.nowarn
import scala.reflect.api.TypeCreator
import scala.runtime.{ BoxesRunTime, ScalaRunTime }
import scala.runtime.{BoxesRunTime, ClassValueCompat, ScalaRunTime}

private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse with TwoWayCaches { thisUniverse: SymbolTable =>

Expand Down Expand Up @@ -120,7 +120,7 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive
private[this] val fieldCache = new TwoWayCache[jField, TermSymbol]
private[this] val tparamCache = new TwoWayCache[jTypeVariable[_ <: GenericDeclaration], TypeSymbol]

private[this] object typeTagCache extends ClassValue[jWeakReference[TypeTag[_]]]() {
private[this] object typeTagCache extends ClassValueCompat[jWeakReference[TypeTag[_]]]() {
val typeCreator = new ThreadLocal[TypeCreator]()

override protected def computeValue(cls: jClass[_]): jWeakReference[TypeTag[_]] = {
Expand Down

0 comments on commit 6c9dd4d

Please sign in to comment.