Search before asking
Version
Apache Fory 1.0.0, Java serializer, CompatibleMode.COMPATIBLE.
The warning is seen in a Java application when scala.Product is loadable from the runtime classpath. The application code and affected serialized classes are Java classes, not Scala classes.
It is enough for the application to depend on some ordinary Java-facing library that happens to pull in Scala transitively. The application does not need to declare org.scala-lang:scala-library directly and does not need to use any Scala APIs.
Component(s)
Java
Minimal reproduce step
Create a small Maven project with Fory 1.0.0, Lombok, and any Java-facing dependency that brings scala-library onto the runtime classpath transitively. The Java code does not need to use Scala; scala-library only needs to be present transitively so org.apache.fory.type.ScalaTypes.SCALA_AVAILABLE becomes true.
pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>repro</groupId>
<artifactId>fory-lombok-default-repro</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.release>17</maven.compiler.release>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.fory</groupId>
<artifactId>fory-core</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
<scope>provided</scope>
</dependency>
<!-- Used only as an example of a Java application dependency that brings scala-library transitively. -->
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.13</artifactId>
<version>3.6.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.12</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.3.0</version>
</plugin>
</plugins>
</build>
</project>
src/main/java/repro/LombokDefaultRepro.java:
package repro;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Value;
import org.apache.fory.Fory;
import org.apache.fory.config.CompatibleMode;
import org.apache.fory.config.Language;
import org.apache.fory.logging.LoggerFactory;
public class LombokDefaultRepro {
@Value
@Builder
@AllArgsConstructor
public static class JavaPojo {
String id;
@Builder.Default
List<String> imageRelations = List.of();
}
public static void main(String[] args) {
LoggerFactory.useSlf4jLogging(true);
Fory fory = Fory.builder()
.withLanguage(Language.JAVA)
.requireClassRegistration(false)
.withCompatibleMode(CompatibleMode.COMPATIBLE)
.build();
byte[] bytes = fory.serialize(JavaPojo.builder().id("1").build());
fory.deserialize(bytes, JavaPojo.class);
}
}
Run:
mvn -q compile exec:java -Dexec.mainClass=repro.LombokDefaultRepro
Confirm that Scala is present transitively:
mvn -q dependency:tree -Dincludes=org.scala-lang:scala-library
Expected dependency path:
repro:fory-lombok-default-repro:jar:1.0-SNAPSHOT
\- org.apache.kafka:kafka_2.13:jar:3.6.2:compile
\- org.scala-lang:scala-library:jar:2.13.11:compile
Lombok compiles @Builder.Default into a private static method whose name has the shape $default$imageRelations():
javap -classpath target/classes -private 'repro.LombokDefaultRepro$JavaPojo'
Relevant output:
private static java.util.List<java.lang.String> $default$imageRelations();
If the Kafka dependency, or any other dependency that makes scala.Product loadable, is removed, the warning is not emitted because the Scala default-value branch is not enabled.
What did you expect to see?
No warning should be emitted for a plain Java class just because Scala is present somewhere on the runtime classpath.
Fory's Scala default-value support should either only inspect Scala types, or it should only treat method names as Scala default methods when the suffix after $default$ is numeric, such as apply$default$1.
What did you see instead?
During deserialization, Fory logs a warning from DefaultValueUtils:
WARN org.apache.fory.util.DefaultValueUtils - Error For input string: "imageRelations" finding default value for repro.LombokDefaultRepro$JavaPojo, default values support is disabled when deserializing object of type repro.LombokDefaultRepro$JavaPojo
This happens even though JavaPojo is a Java class and the repro does not call any Kafka or Scala APIs. The only Scala-related condition is that scala.Product is loadable from the classpath via a transitive dependency.
Anything Else?
The suspected path is:
CompatibleSerializer enables Scala default-value support when ScalaTypes.SCALA_AVAILABLE is true.
ScalaTypes.SCALA_AVAILABLE is global and becomes true when scala.Product can be loaded.
DefaultValueUtils.ScalaDefaultValueSupport#getDefaultValuesForRegularScalaClass scans all declared methods whose names contain $default$.
- It then parses the substring after
$default$ as an integer.
- Lombok
@Builder.Default generates methods like $default$imageRelations, where the suffix is a Java field name, not a Scala argument index.
This makes a transitive Scala dependency enough to produce warning noise for Java Lombok model classes. In practice this can happen just by adding a Java-facing library whose own dependency graph includes Scala, even if the application is otherwise pure Java.
Are you willing to submit a PR?
Search before asking
Version
Apache Fory 1.0.0, Java serializer,
CompatibleMode.COMPATIBLE.The warning is seen in a Java application when
scala.Productis loadable from the runtime classpath. The application code and affected serialized classes are Java classes, not Scala classes.It is enough for the application to depend on some ordinary Java-facing library that happens to pull in Scala transitively. The application does not need to declare
org.scala-lang:scala-librarydirectly and does not need to use any Scala APIs.Component(s)
Java
Minimal reproduce step
Create a small Maven project with Fory 1.0.0, Lombok, and any Java-facing dependency that brings
scala-libraryonto the runtime classpath transitively. The Java code does not need to use Scala;scala-libraryonly needs to be present transitively soorg.apache.fory.type.ScalaTypes.SCALA_AVAILABLEbecomes true.pom.xml:src/main/java/repro/LombokDefaultRepro.java:Run:
Confirm that Scala is present transitively:
Expected dependency path:
Lombok compiles
@Builder.Defaultinto a private static method whose name has the shape$default$imageRelations():javap -classpath target/classes -private 'repro.LombokDefaultRepro$JavaPojo'Relevant output:
If the Kafka dependency, or any other dependency that makes
scala.Productloadable, is removed, the warning is not emitted because the Scala default-value branch is not enabled.What did you expect to see?
No warning should be emitted for a plain Java class just because Scala is present somewhere on the runtime classpath.
Fory's Scala default-value support should either only inspect Scala types, or it should only treat method names as Scala default methods when the suffix after
$default$is numeric, such asapply$default$1.What did you see instead?
During deserialization, Fory logs a warning from
DefaultValueUtils:This happens even though
JavaPojois a Java class and the repro does not call any Kafka or Scala APIs. The only Scala-related condition is thatscala.Productis loadable from the classpath via a transitive dependency.Anything Else?
The suspected path is:
CompatibleSerializerenables Scala default-value support whenScalaTypes.SCALA_AVAILABLEis true.ScalaTypes.SCALA_AVAILABLEis global and becomes true whenscala.Productcan be loaded.DefaultValueUtils.ScalaDefaultValueSupport#getDefaultValuesForRegularScalaClassscans all declared methods whose names contain$default$.$default$as an integer.@Builder.Defaultgenerates methods like$default$imageRelations, where the suffix is a Java field name, not a Scala argument index.This makes a transitive Scala dependency enough to produce warning noise for Java Lombok model classes. In practice this can happen just by adding a Java-facing library whose own dependency graph includes Scala, even if the application is otherwise pure Java.
Are you willing to submit a PR?