Skip to content

Strange forwarder method generated by the Scala 3 compiler #25098

@vasilmkd

Description

@vasilmkd

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 JTable

produces 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.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions