Compile error using swing code

Dear folks

I’ve found a problem with Scala 2.13.2 while reviewing a code. Here I bring the simple and small as possible piece of code with respective error messages. The errors occur in both using Scalac and Dotty in command line (scalac ComboBoxProblem.scala), no IDE. This code use to compile in previews versions of Scala. If the comments are removed there is only the second error. A compile error that I couldn’t solve. A solution would be very welcomed.

Thanks


ComboBoxProblem.scala

import javax.swing.plaf.basic.ComboPopup
import javax.swing.plaf.basic.BasicComboPopup
import javax.swing.plaf.basic.BasicComboBoxUI
import javax.swing.JComboBox
import java.io.Serializable

object AbstractInterface {}
abstract class AbstractInterface {}

@SerialVersionUID(1L)
trait ComboBoxChild[T] extends JComboBox[T] with Serializable {

val comboClass = new ComboBoxClass()

protected class ComboBoxClass extends BasicComboBoxUI {

override protected def createPopup(): ComboPopup = {
  val popupChild = new ComboPopupChild(comboBox.asInstanceOf[JComboBox[AbstractInterface]])
  //popupChild.getAccessibleContext.setAccessibleParent(comboBox)
  //popupChild
  }

}

@SerialVersionUID(1L)
protected class ComboPopupChild(comboChild: JComboBox[AbstractInterface]) extends BasicComboPopup( comboChild) {}

}

ComboBoxProblem.scala:26: error: type mismatch;
found : Unit
required: javax.swing.plaf.basic.ComboPopup
}
^
ComboBoxProblem.scala:30: error: type mismatch;
found : javax.swing.JComboBox[AbstractInterface]
required: javax.swing.JComboBox[Object]
Note: AbstractInterface <: Object, but Java-defined class JComboBox is invariant in type E.
You may wish to investigate a wildcard type such as _ <: Object. (SLS 3.2.10)
protected class ComboPopupChild(comboChild: JComboBox[AbstractInterface]) extends BasicComboPopup( comboChild) {}
^
2 errors

It is because the following expression’s type is Unit:
val popupChild = …

Your subsequent lines are all comments.

If I uncomment those two lines, the code compiles fine on both Scala 2.13.2 and 2.13.3. I don’t get the “type mismatch” error.

OK, people could run it also in Scastie with no problems. I’m using Java

openjdk version “11.0.8” 2020-07-14
OpenJDK Runtime Environment (build 11.0.8+10-suse-lp151.3.19.1-x8664)
OpenJDK 64-Bit Server VM (build 11.0.8+10-suse-lp151.3.19.1-x8664, mixed mode)

And Scala

Scala code runner version 2.13.2 – Copyright 2002-2020, LAMP/EPFL and Lightbend, Inc.

All in Linux OpenSuse 15.1. The errors are there. It seems a bug in some point of this environment. Either the bug is fixed or I need to find a work around, yet thanks for the answer because I’ll focus in environment rather than code that is correct.

Again, thanks

Oh, I know what this is, it’s a Java 8 vs 11 thing. The type mismatch error is reproducible for me if I use Java 11. Oracle made source-incompatible changes to the Swing APIs. I don’t know the details.

100% YES!!! I did the exactly same test, and it did work for Java 8!!!

By setting the path for the appropriate Java

export JAVA_HOME=/usr/lib64/jvm/java-1.8.0/

It did run perfectly.

Case solved, we know what NOT to do: Don’t use Java 11.

Thanks for the help.

Don’t use Java 15 too!!!

Just for the record: this compilation issue is way much more serious knowing that the Scala swing code compiled in Java 8 will crash in Java 11, meaning you must keep an out of date JVM to run any Scala code.

Well, at least one side, either Scala or Java, or both, must fix this issue, otherwise any advance will always have to rely on an old technology.

The problem is simply that Scala Swing is “mostly unsupported”. Not enough manpower to maintain it adequately. Either use Java Swing directly (from Scala, but not using Scala Swing), or use something else (maybe ScalaFX?).

Eh? “use Java Swing directly” is exactly what OP is already doing. This doesn’t involve the scala-swing module.

What is the runtime crash, how does that come about?

How certain are you that the problem isn’t in your code? You seem quite certain, but you haven’t demonstrated it to the rest of us.

Ah, right, sorry. I thought “Scala swimming code” referred to using Scala Swing, but apparently, it just meant “Scala code using Swing”.

In that case, I don’t understand how this is a Scala problem at all? Wouldn’t the same problem occur if they used Java instead?

1 Like

Indeed, that’s what I suspect.

(But I haven’t dug into it enough to be certain. Maybe things would be different in Java because of use-site variance vs. declaration-site variance? The other relevant Java/Scala difference is that the Scala type system allows primitive types as type parameters, and Java doesn’t. As a result in Scala sometimes you may need an <: AnyRef or something like that.)

1 Like

I’ve seen a program that works perfectly in Java 8 but crashes in Java 11, which is not my code, actually a large project, which I don’t think it is possible a small sample. It would be nice of course an example to check. For the time being just trust, and hopefullly all will be fixed in the near future.

Anyway thanks

1 Like

They changed the constructor of BasicComboBox between Java 8 and Java 11:

https://docs.oracle.com/javase/8/docs/api/javax/swing/plaf/basic/BasicComboPopup.html#BasicComboPopup-javax.swing.JComboBox-

public BasicComboPopup(JComboBox combo)

vs.

https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/swing/plaf/basic/BasicComboPopup.html#<init>(javax.swing.JComboBox)

public BasicComboPopup​(JComboBox<Object> combo)

The former using a raw type of the generic class JComboBox, the latter – properly – using a type argument for the generic class. This clashes now, since you tried to pass a JComboBox[AbstractInterface] instead of a JComboBox[AnyRef].

You can fix the code for both JVM targets:

  @SerialVersionUID(1L)
  protected class ComboPopupChild(comboChild: JComboBox[AbstractInterface])
      extends BasicComboPopup(comboChild.asInstanceOf[JComboBox[AnyRef]]) {}
1 Like

Everything is terrible. Thanks for getting to the bottom of this.

That still shouldn’t cause a runtime crash though, or am I missing something?

Right. I suppose that there’s a different reason for the runtime crash.

Hi

I could find and separate the piece of code that compiles and run in Java 8 but crashes in Java 11 (the compíled Java 8 ). It is just to complete the discussion. The code is:

RunTimeProblem.java

public class RunTimeProblem {

public static void main(String[] args) {

    System.out.println("RunTimeProblem");
    
     try {
        
        final ClassLoader classLoader = new ChildClassLoader(new String("String"));
        
        final Class childClass = Class.forName("ClassName", false, classLoader);
        
    } catch (ClassNotFoundException ex) { }
}

}

ChildClassLoader.java

import java.net.URLClassLoader;

public final class ChildClassLoader extends ClassLoader {

private final String childString;

 public ChildClassLoader(final String string) {
    
    childString = string;        
    System.out.println("ChildClassLoader");
}

@Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {

        final URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        return super.findClass(name);
}

}

With the following error message in Java 11:

RunTimeProblem
ChildClassLoader
Exception in thread “main” java.lang.ClassCastException: class jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to class java.net.URLClassLoader (jdk.internal.loader.ClassLoaders$AppClassLoader and java.net.URLClassLoader are in module java.base of loader ‘bootstrap’)
at ChildClassLoader.findClass(ChildClassLoader.java:18)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:398)
at RunTimeProblem.main(RunTimeProblem.java:15)

Java 8 X Java 11, let’s see.

1 Like

That’s an unsafe code by definition, i.e. unsafe cast. You don’t have guarantee that there’s a URLClassLoader. You have to test for multiple possibilities.

3 Likes