-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Compiler version
3.8.1
Minimal project definition
// build.sbt
lazy val root = project.in(file("."))
.settings(
name := "jtable-forwarder",
scalaVersion := "3.8.1"
)// src/main/scala/org/example/MyJTable.scala
package org.example
import javax.swing.JTable
class MyJTable extends JTableproduces the following bytecode (decompiled back to Java).
//
// Source code recreated by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
//decompiled from MyJTable.class
package org.example;
import java.awt.Point;
import javax.swing.JTable;
import javax.swing.TransferHandler;
import javax.swing.plaf.ComponentUI;
public class MyJTable extends JTable {
public MyJTable() {
}
// $FF: synthetic method
// $FF: bridge method
public TransferHandler.DropLocation dropLocationForPoint(final Point x$0) {
return this.dropLocationForPoint(x$0);
}
// $FF: synthetic method
// $FF: bridge method
public ComponentUI getUI() {
return this.getUI();
}
}The public TransferHandler.DropLocation dropLocationForPoint(final Point x$0) method is a bit controversial. It is a forwarder method to the package-private method with the same name defined in javax.swing.JTable. It essentially relaxes the accessibility modifier of a package-private method.
As an example, the IntelliJ Plugin API Checker flagged this method as potentially unsafe with the following warning (we have a class like this in the Scala Plugin for IntelliJ IDEA).
Method org.jetbrains.sbt.project.MigrateConfigurationsDialogWrapper$.anon$1.dropLocationForPoint(Point) : TransferHandler.DropLocation contains an *invokevirtual* instruction referencing org.jetbrains.sbt.project.MigrateConfigurationsDialogWrapper$.anon$1.dropLocationForPoint(java.awt.Point) : javax.swing.JTable.DropLocation which is resolved to a package-private method javax.swing.JTable.dropLocationForPoint(java.awt.Point) : javax.swing.JTable.DropLocation inaccessible to a class org.jetbrains.sbt.project.MigrateConfigurationsDialogWrapper$.anon$1. This can lead to **IllegalAccessError** exception at runtime.
As a workaround, we rewrote the class using Java.
This warning was raised after we migrated a bit of code to Scala 3. Scala 2 did not generate this forwarder method. Here's bytecode produced by Scala 2.13.18.
//
// Source code recreated by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
//decompiled from MyJTable.class
package org.example;
import javax.swing.JTable;
import scala.reflect.ScalaSignature;
@ScalaSignature(
bytes = "\u0006\u0005U1AAA\u0002\u0001\u0011!)\u0011\u0003\u0001C\u0001%\tAQ*\u001f&UC\ndWM\u0003\u0002\u0005\u000b\u00059Q\r_1na2,'\"\u0001\u0004\u0002\u0007=\u0014xm\u0001\u0001\u0014\u0005\u0001I\u0001C\u0001\u0006\u0010\u001b\u0005Y!B\u0001\u0007\u000e\u0003\u0015\u0019x/\u001b8h\u0015\u0005q\u0011!\u00026bm\u0006D\u0018B\u0001\t\f\u0005\u0019QE+\u00192mK\u00061A(\u001b8jiz\"\u0012a\u0005\t\u0003)\u0001i\u0011a\u0001"
)
public class MyJTable extends JTable {
public MyJTable() {
}
}Why is this forwarder method generated? Is it necessary? Is it even safe? Thanks in advance.