2

I want to call a Java method with the following API from Scala:

// Java API
public interface JavaAPI {
  JustSomeAPISpecificType clone();
}

// Scala code in class a.b.c.D
val api: JavaAPI = factory.getAPI
val result: JustSomeAPISpecificType = api.clone

However, this does not work, as the Scala compiler (2.10) thinks I want to call Object.clone:

Error: method clone in class Object cannot be accessed in Option[JavaAPI] Access to protected method clone not permitted because prefix type Option[JavaAPI] does not conform to class D in package a.b.c where the access take place

Any ideas? Thanks.

Michael Rueegg
  • 765
  • 4
  • 13

1 Answers1

2

First of all see Object#clone() signature

protected Object clone()
                throws CloneNotSupportedException

You want to override this method.

In your example now you have two methods:

protected Object clone()
                    throws CloneNotSupportedException
public JustSomeAPISpecificType clone()

See:

JustSomeAPISpecificType.java

public enum JustSomeAPISpecificType{
INSTANCE
}

Factory.java

public class Factory {

        public static class JavaApiImpl implements JavaAPI{

                public JustSomeAPISpecificType clone(){
                        return JustSomeAPISpecificType.INSTANCE;
                }
        }

        public static JavaAPI getAPI(){
                return new JavaApiImpl();
        }
}

Now add your files to src/main/java and run sbt console from root:

scala> val api = Factory.getAPI
api: JavaAPI = Factory$JavaApiImpl@4243eb68

scala> api.getClass.getMethods.filter(m => m.getName.startsWith("clone")).mkString("\n")
res0: String = 
public JustSomeAPISpecificType Factory$JavaApiImpl.clone()
public java.lang.Object Factory$JavaApiImpl.clone() throws java.lang.CloneNotSupportedException

Update If you cast - you will see the method clone (if the factory is public).

scala> api.asInstanceOf[Factory.JavaApiImpl].clone
res4: JustSomeAPISpecificType = INSTANCE
Andrzej Jozwik
  • 14,331
  • 3
  • 59
  • 68
  • Thanks for your comment, but it's the API of a given Java library that provides this clone method. How can I convince the Scala compiler to use JavaAPI.clone() now? – Michael Rueegg Sep 09 '14 at 07:15
  • Try the reflection api. But you want to break the rules. See [clone contract](http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#clone--) `x.clone().getClass() == x.getClass()`. – Andrzej Jozwik Sep 09 '14 at 07:22
  • Okay, thank you, by using reflection I'm able to call clone() of the Java API, although I was hoping for a more elegant solution... By the way, I'm aware of the clone contract and don't want to break it. It's just the Java library I'm using. – Michael Rueegg Sep 09 '14 at 08:17
  • This is bug is scala. See https://groups.google.com/forum/#!topic/scala-user/WaMDZqm8CC0 or http://stackoverflow.com/a/15861169/651140 – Andrzej Jozwik Sep 09 '14 at 09:09
  • Thanks, but unfortunately the Java factory is not public. I can live with the reflection approach for now. But note that the bug you mentioned was fixed in Scala 2.7.2 according to the bug tracker and I'm using 2.10.3. – Michael Rueegg Sep 09 '14 at 09:38
  • It was solved - and again occurred. It is regression. Your code is a good test. – Andrzej Jozwik Sep 09 '14 at 09:55
  • I use reflection for now until this bug is fixed and mark this as resolved. – Michael Rueegg Sep 09 '14 at 10:00