bbarker
bbarker

Reputation: 13088

How to enrich a Java library class that has static methods (aka enrich an object in Scala)?

I'm trying to extend a class (SWT.java) from a Java library (SWT) that only has static final members. An excerpt from the library class:

package org.eclipse.swt;
import org.eclipse.swt.internal.*;

public class SWT {
    public static final int None = 0;
    // ...
    public static final int MouseDown = 3;
    // ...
}

My Java wrapper class that worked fine in Java land:

public class SWT extends org.eclipse.swt.SWT {
    public static final int FinalizeText = 201;
    public static final int ParseText = 202;
}

Now if I try to use my new SWT class in Scala, I'll get errors like this:

Error:(198, 27) value MouseDown is not a member of object my.package.SWT
    table.addListener(SWT.MouseDown, periodEditListener)
                          ^

Ideally I would like a new SWT object with which I could access both original members (e.g. MouseDown) and members I define (e.g. FinalizeText).

It seems that Scala interprets everything useful about this class as an object, which is fine if we just want to use the original SWT definitions, but you can't easily extend objects in Scala.

It has occurred to me that implicits a la pimp my library might be the way to go, but even were I to get this to work, I think the solution would not be accessible from Java (still, I have not even gotten in to work in Scala).

How to best tackle the problem? Maybe the right answer is to just define a separate, unrelated object.

Upvotes: 2

Views: 612

Answers (2)

bbarker
bbarker

Reputation: 13088

I am accepting yuzeh's answer for thoroughness, general applicability, and helpfulness, but here is what I actually did, which is slightly different:

I was very tempted by yuzeh's last suggestion for the sake of uniformity, i.e.

import org.eclipse.swt.SWT._
import my.package.SWT._

Although as my first example snippet above inadvertently shows, SWT.None unfortunately is, so bringing it into the local namespace would conflict with Option's None.

I think for now I'll just import like:

import org.eclipse.swt.SWT
import my.package.{SWT => MySWT}

If nothing else, it is a bit more clear where the constants are coming from. There, I talked myself into believing this is better :).

Upvotes: 0

yuzeh
yuzeh

Reputation: 442

I don't think there is a good way to do what you want such that:

  • You can neatly tie all members to an identifier (i.e. refer to the field via SWT.X instead of X)
  • Have it work both in Scala and Java.
  • You don't have to manually forward fields.

This is a documented limitation of Scala -- see access java base class's static member in scala.

In addition, I don't think the implicit route works either, because you can't treat a Java class as a value: How to access a Java static method from Scala given a type alias for that class it resides in

Probably the best way to do what you want is to manually forward the static members you need in my.package.SWT:

public class SWT extends org.eclipse.swt.SWT {
    public static final int FinalizeText = 201;
    public static final int ParseText = 202;
    public static int getMouseDown() {
        return MouseDown;
    }
}

If you only care about automatically forwarding members and not about the other requirements, you can use import:

import org.eclipse.swt.SWT._
table.addListener(MouseDown, periodEditListener)

Upvotes: 2

Related Questions