diff --git a/akka-actor-tests/src/test/scala/akka/util/ByteStringInitializationSpec.scala b/akka-actor-tests/src/test/scala/akka/util/ByteStringInitializationSpec.scala new file mode 100644 index 0000000000..c47f6516a7 --- /dev/null +++ b/akka-actor-tests/src/test/scala/akka/util/ByteStringInitializationSpec.scala @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2020 Lightbend Inc. + */ + +package akka.util + +import java.io.InputStream + +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec + +import scala.collection.mutable +import scala.collection.mutable.ArrayBuilder + +class ByteStringInitializationSpec extends AnyWordSpec with Matchers { + "ByteString intialization" should { + "not get confused by initializing CompactByteString before ByteString" in { + // a classloader that creates a new universe of classes for everything beneath akka + // that prevents that this test interacts with any tests + val cleanCl = new ClassLoader(null) { + val outerCl = ByteStringInitializationSpec.this.getClass.getClassLoader + val buffer = new Array[Byte](1000000) + override def loadClass(name: String): Class[_] = + if (!name.startsWith("akka")) outerCl.loadClass(name) + else { + val classFile = name.replace(".", "/") + ".class" + val is = outerCl.getResourceAsStream(classFile) + val res = slurp(is, new mutable.ArrayBuilder.ofByte) + defineClass(name, res, 0, res.length) + } + + def slurp(is: InputStream, res: ArrayBuilder[Byte]): Array[Byte] = { + val read = is.read(buffer) + if (read == 0) throw new IllegalStateException + else if (read > 0) slurp(is, res ++= buffer.take(read)) + else res.result() + } + } + + import scala.language.reflectiveCalls + type WithRun = { def run(): Unit } + cleanCl.loadClass("akka.util.ByteStringInitTest").newInstance().asInstanceOf[WithRun].run() + } + } +} + +class ByteStringInitTest { + def run(): Unit = { + require(CompactByteString.empty ne null) + require(ByteString.empty ne null) + } +} diff --git a/akka-actor/src/main/scala-2.13/akka/util/ByteString.scala b/akka-actor/src/main/scala-2.13/akka/util/ByteString.scala index 749200d9c4..3c38b68619 100644 --- a/akka-actor/src/main/scala-2.13/akka/util/ByteString.scala +++ b/akka-actor/src/main/scala-2.13/akka/util/ByteString.scala @@ -747,7 +747,7 @@ sealed abstract class ByteString override protected def fromSpecific(coll: IterableOnce[Byte]): ByteString = ByteString(coll) override protected def newSpecificBuilder: mutable.Builder[Byte, ByteString] = ByteString.newBuilder - override val empty: ByteString = ByteString.empty + override def empty: ByteString = ByteString.empty def apply(idx: Int): Byte private[akka] def byteStringCompanion: ByteString.Companion