Skip to content

Instantly share code, notes, and snippets.

@djspiewak
Created March 14, 2022 00:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save djspiewak/423c26f4ed8147d0e97b03ee3c406d03 to your computer and use it in GitHub Desktop.
Save djspiewak/423c26f4ed8147d0e97b03ee3c406d03 to your computer and use it in GitHub Desktop.
/*
* Copyright 2020-2022 Typelevel
*
* 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 scala.runtime
import java.io.Serializable
import java.security.PrivilegedActionException
import java.security.PrivilegedExceptionAction
import scala.annotation.nowarn
private[runtime] object ModuleSerializationProxy {
private val instances = new ClassValueCompat[Object] {
@nowarn("cat=deprecation") // AccessController is deprecated on JDK 17
def getModule(cls: Class[_]): Object =
java.security.AccessController.doPrivileged(
(() => cls.getField("MODULE$").get(null)): PrivilegedExceptionAction[Object])
override protected def computeValue(cls: Class[_]): Object =
try getModule(cls)
catch {
case e: PrivilegedActionException =>
rethrowRuntime(e)
}
}
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)
}
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
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment