Migrating Java code to Scala - what went wrong?

I migrated this Java code

public class ToggleAdapter implements Toggle {
    final private TitledPane titledPane;
    final private ObjectProperty<ToggleGroup> toggleGroupProperty = new SimpleObjectProperty<>();

    @Override
    public ToggleGroup getToggleGroup() {
        return toggleGroupProperty.get();
    }

    @Override
    public void setToggleGroup(ToggleGroup toggleGroup) {
        toggleGroupProperty.set(toggleGroup);
    }

    @Override
    public ObjectProperty<ToggleGroup> toggleGroupProperty() {
        return toggleGroupProperty;
    }

    @Override
    public boolean isSelected() {
        return titledPane.isExpanded();
    }

    @Override
    public void setSelected(boolean selected) {
        titledPane.setExpanded(selected);
    }

    @Override
    public BooleanProperty selectedProperty() {
        return titledPane.expandedProperty();
    }

    @Override
    public Object getUserData() {
        return titledPane.getUserData();
    }

    @Override
    public void setUserData(Object value) {
        titledPane.setUserData(value);
    }

    @Override
    public ObservableMap<Object, Object> getProperties() {
        return FXCollections.emptyObservableMap();
    }

    public static Toggle asToggle(final TitledPane titledPane) {
        return new ToggleAdapter(titledPane);
    }

    public ToggleAdapter(TitledPane titledPane) {
        this.titledPane = titledPane;

        selectedProperty().addListener(obs -> {
            Optional.ofNullable(getToggleGroup()).ifPresent(toggleGroup -> {
                if (isSelected()) {
                    toggleGroup.selectToggle(this);
                } else if (toggleGroup.getSelectedToggle() == this) {
                    toggleGroup.selectToggle(null);
                }
            });
        });
    }
}

to this Scala code:

class TitledPaneToggleAdapter(titledPane: TitledPane) extends Toggle {
  override val toggleGroupProperty: ObjectProperty[ToggleGroup] = new SimpleObjectProperty[ToggleGroup]()

  override def getToggleGroup: ToggleGroup = toggleGroupProperty.get()

  override def setToggleGroup(toggleGroup: ToggleGroup): Unit = toggleGroupProperty.set(toggleGroup)

  override def isSelected: Boolean = titledPane.isExpanded

  override def setSelected(b: Boolean): Unit = titledPane.setExpanded(b)

  override def selectedProperty(): BooleanProperty = titledPane.expandedProperty()

  override def getUserData: AnyRef = titledPane.getUserData

  override def setUserData(o: Any): Unit = titledPane.setUserData(o)

  override def getProperties: ObservableMap[AnyRef, AnyRef] = FXCollections.emptyObservableMap()

  selectedProperty().addListener(_ => {
    Option(getToggleGroup).foreach(toggleGroup => {
      if (isSelected) {
        toggleGroup.selectToggle(this)
      } else if (toggleGroup.getSelectedToggle == this) {
        toggleGroup.selectToggle(null)
      }
    })
  })
}

object TitledPaneToggleAdapter {
  def apply(titledPane: TitledPane): Toggle = new TitledPaneToggleAdapter(titledPane)
}

In my opinion, the Java code and the Scala code should be equivalent. But if I put it to the test it is not.

Concerning only the code: Did I miss anything? Did I migrate the code correctly?

Can you describe what works and doesn’t work, and what you have done to try to resolve it? You’re much more likely to get an answer if you provide information beyond the code itself.

1 Like

Thank you for your response!

It’s not quite easy to explain what it does and what does not work, but let me try:

TitledPaneToggleAdapter is an adapter that allows for TitledPanes to be handled like RadioButtons or RadioMenuItems within a ToggleGroup. Added to a ToggleGroup only one of the TitledPanes shall be allowed to be expanded; if another TitledPane is triggered to expand, the already expanded one shall collapse.

The Java implementation does what it is supposed to do; however, the Scala implementation is not, it does not anything but I don’t see why, to be the migration of the Java code to Scala is correct, and that’s why I started to wonder that my assessment is wrong.

Does it make a difference if you put this code at the end of your class?

  selectedProperty().addListener(_ => {
    Option(getToggleGroup).foreach(toggleGroup => {
      if (isSelected) {
        toggleGroup.selectToggle(this)
      } else if (toggleGroup.getSelectedToggle == this) {
        toggleGroup.selectToggle(null)
      }
    })
  })
1 Like

I just tried it: Unfortunately doesn’t change a thing.

Update: To rule out that the implementation where TitledPaneToggleAdapter is used is the problem, I briefly included the Java variant, and it works fine with that. So there must be some problem with my Scala code.

Java variables are mutable. So the corresponding Scala variables for titledPane and toggleGroupProperty should be declared with var.

I see:

 private val _toggleGroupProperty

Is this correct? Same for titledPane: TitledPane.

HTHs

You are right, this should be var. But in this case it does not change the behaviour.

(titledPane is, as it is declared in the constructor, is implicitly a val.)

The titledPane argument being passed in is not assigned to anything in your Adapter.

You’d need to do the equivalent of the java initial assignment on the constructor.

To do so you can

a. define a private val _titledPane = titledPane in your class and then refer to _titledPane in all your methods.
b. obtain the same effect by changing the input parameter in the signature to private val as in
class TitledPaneToggleAdapter(private val titledPane: TitledPaned) extends Toggle {...}

I’m not guaranteeing this will solve your faulty behaviour, but it would be more adherent to the original code.
Which could actually change things, since you might not be modifying the correct instance?

:man_shrugging:

Constructor arguments are implicitly turned into private[this] val if they are used outside of the constructor (i.e. in a method).

By the way, you should be able to implement toggleGroupProperty as

override val toggleGroupProperty: ObjectProperty[ToggleGroup] = new SimpleObjectProperty[ToggleGroup]()

and drop the private val _toggleGroupProperty.

1 Like

True that, this was lingering around frome some previous experiments. I will modify my example.

I just don’t understand how my Scala implementation is not equal to the Java code.

Is there some tool that transforms Java code into Scala? So I could try this to see if there is a difference to mine.

In the code after the most recent edit, you will probably want to replace the override def with override val:

// current
override def toggleGroupProperty(): ObjectProperty[ToggleGroup] = new SimpleObjectProperty[ToggleGroup]()

// should be
override val toggleGroupProperty(): ObjectProperty[ToggleGroup] = new SimpleObjectProperty[ToggleGroup]()

As to the converter: IntelliJ is capable of converting code on the fly, and a quick google search turned up http://javatoscala.com/ (not up-to date at all, but may be a starting point)

Correct, I should replace the override with val; but this, of course, does not solve the issue that it does not work.

Wouldn’t have hoped so - but any future reader trying to analyze the code from your example will have a greater chance to spot the issue if they don’t stumble over that unrelated, though obvious, difference - so I thought I’d state the obvious.

After all, without the full code, this will have to be an incremental improvement towards the Java and Scala code being as close to each other as possible.

You’re right, did it.

Sorry for bothering again: You seem to have accidentally turned the wrong method into a val.

The code as it is now still creates a fresh new SimpleObjectProperty[ToggleGroup]() every time the method toggleGroupProperty() is called - effectively losing any state that is ever assigned to it.

No worries :slight_smile: I did it now in an edtior to see what I do. Now it should be the right one.