Description
Search before asking
- I had searched in the issues and found no similar issues.
Version
➜ fury-test sw_vers
ProductName: macOS
ProductVersion: 15.4.1
BuildVersion: 24E263
➜ fury-test java -version
openjdk version "21.0.4.0.101" 2024-10-15 LTS
OpenJDK Runtime Environment Zulu21.37+12-SA (build 21.0.4.0.101+1-LTS)
OpenJDK 64-Bit Server VM Zulu21.37+12-SA (build 21.0.4.0.101+1-LTS, mixed mode)
Salesforce OneJDK 21.0.4.0.101+34 2024-11-20
➜ fury-test sbt -version
sbt version in this project: 1.10.11
sbt runner version: 1.10.11
➜ fury-test cat build.sbt| grep scalaVersion
scalaVersion := "2.13.15"
➜ fury-test cat build.sbt| grep org.apache.fury
libraryDependencies += "org.apache.fury" % "fury-scala_2.13" % "0.10.2"
Component(s)
Other, Java
Minimal reproduce step
Main.scala
import org.apache.fury.{ Fury, ThreadSafeFury }
import org.apache.fury.serializer.scala.ScalaSerializers
import java.nio.file.{Paths, Files}
import java.nio.charset.StandardCharsets
object Main extends App {
val threadSafeFury: ThreadSafeFury = Fury
.builder()
.withScalaOptimizationEnabled(true)
.requireClassRegistration(false)
.withRefTracking(true)
.buildThreadSafeFury()
ScalaSerializers.registerSerializers(threadSafeFury)
case class ThisReturnsNullUntilSerializeIsCalled(param: String)
// Uncomment this line to generate the test file. Comment it out to reproduce the issue after generating the file
// Files.write(Paths.get("test.txt"), threadSafeFury.serialize(ThisReturnsNullUntilSerializeIsCalled))
// Registering the class resolves the issue
//threadSafeFury.register(Main.ThisReturnsNullUntilSerializeIsCalled.getClass)
// Stored the serialized bytes in a previous run
val byteArray = Files.readAllBytes(Paths.get("test.txt"))
// This should print `ThisReturnsNullUntilSerializeIsCalled` but prints `null`
println(threadSafeFury.deserialize(byteArray))
// After this call deserialization works
val bytes = threadSafeFury.serialize(ThisReturnsNullUntilSerializeIsCalled)
// Prints `ThisReturnsNullUntilSerializeIsCalled`
println(threadSafeFury.deserialize(byteArray))
// Write out again to ensure that the file is up to date
Files.write(Paths.get("test.txt"), bytes)
}
build.sbt
scalaVersion := "2.13.15"
name := "hello-world"
organization := "ch.epfl.scala"
version := "1.0"
libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "2.3.0"
libraryDependencies += "org.apache.fury" % "fury-scala_2.13" % "0.10.2"
What did you expect to see?
sbt:hello-world> run
[info] compiling 1 Scala source to /Users/chethan.reddy/tmp/fury-test/fury-test/target/scala-2.13/classes ...
[info] running Main
2025-05-20 09:29:16 WARN FuryBuilder:427 [sbt-bg-threads-9] - Class registration isn't forced, unknown classes can be deserialized. If the environment isn't secure, please enable class registration by `FuryBuilder#requireClassRegistration(true)` or configure ClassChecker by `ClassResolver#setClassChecker`
2025-05-20 09:29:16 INFO Fury:159 [sbt-bg-threads-9] - Created new fury org.apache.fury.Fury@39db8b6
ThisReturnsNullUntilSerializeIsCalled
ThisReturnsNullUntilSerializeIsCalled
[success] Total time: 0 s, completed May 20, 2025, 9:29:16 AM
What did you see instead?
sbt:hello-world> run
[info] running Main
2025-05-20 09:28:45 WARN FuryBuilder:427 [sbt-bg-threads-7] - Class registration isn't forced, unknown classes can be deserialized. If the environment isn't secure, please enable class registration by `FuryBuilder#requireClassRegistration(true)` or configure ClassChecker by `ClassResolver#setClassChecker`
2025-05-20 09:28:45 INFO Fury:159 [sbt-bg-threads-7] - Created new fury org.apache.fury.Fury@784533a7
null
ThisReturnsNullUntilSerializeIsCalled
[success] Total time: 0 s, completed May 20, 2025, 9:28:45 AM
Anything Else?
We're using the class as a kind of Enum. Here's a different example:
import org.apache.fury.{ Fury, ThreadSafeFury }
import org.apache.fury.serializer.scala.ScalaSerializers
import java.nio.file.{Paths, Files}
import java.nio.charset.StandardCharsets
object Main extends App {
val threadSafeFury: ThreadSafeFury = Fury
.builder()
.withScalaOptimizationEnabled(true)
.requireClassRegistration(false)
.withRefTracking(true)
.buildThreadSafeFury()
ScalaSerializers.registerSerializers(threadSafeFury)
sealed trait VehicleType { def name: String; def id: Int }
object VehicleType {
case object Bus extends VehicleType { val name = "Bus"; val id = 0 }
case object Car extends VehicleType { val name = "Car"; val id = 1 }
}
object Transportation {
case class Default(
id: Long,
tpe: VehicleType
)
}
val travelMethod = Transportation.Default(
id = 10L,
tpe = VehicleType.Car)
if (!Files.exists(Paths.get("car.txt"))) {
Files.write(Paths.get("car.txt"), threadSafeFury.serialize(travelMethod))
}
val byteArray = Files.readAllBytes(Paths.get("car.txt"))
println(threadSafeFury.deserialize(byteArray))
}
When we first run the program, the file car.txt
is created and the program outputs:
Default(10,Car)
Then, if we modify travelMethod
to
val travelMethod = Transportation.Default(
id = 10L,
tpe = VehicleType.Bus)
Running the program again without any other changes outputs:
Default(10,null)
Are you willing to submit a PR?
- I'm willing to submit a PR!