2

For some special use-case I have a small utility to load Java classes from jars using a dynamic class loader DynamicClassLoader. This works fine for Java classes contained in jars. Loading Scala classes from a jar also works without problems. However, instantiating the loaded Scala class leads to the following exception. It looks like the Scala class has private default constructor? Note the compiled Scala class name ending with $

java.lang.IllegalAccessException: Class XXX can not access a member of class ScalaClassYYY$ with modifiers "private"

The snippet below illustrates the idea of what I'm trying to achieve and gives a bit more context. The exception happens at the annotated line:

// deploy and register the new code
byte[] jarBytes = (byte[]) ((Object) message.getAttachment("jar"));
String registerClassName = message.getAttachment("register");
logger.debug("the register is '" + registerClassName + "'");

DynamicClassLoader loader = new DynamicClassLoader(jarBytes);
Class<?> registerClass = loader.lookUp(registerClassName);
// ===> this is where the java.lang.IllegalAccessException happens 
IRegisterExecutor registerExecutor = (IRegisterExecutor) registerClass.newInstance();
registerExecutor.register();

Any ideas how to fix?

SkyWalker
  • 13,729
  • 18
  • 91
  • 187

1 Answers1

5

Obviously, you need to make the default constructor public (it won't work for Java classes without a public default constructor either). E.g.

class ScalaClassYYY() {
  ...
}

or if you want primary constructor to take some arguments,

class ScalaClassYYY(arg1: Int) {
  def this() = this(0)
}

But from

Note the compiled Scala class name ending with $

it seems like you are actually trying to instantiate a Scala object:

object ScalaClassYYY { ... }

In this case, you shouldn't create a new instance and instead use the existing one:

(IRegisterExecutor) registerClass.getField("MODULE$").get(null);

EDIT:

I don't see in your answer how you add a default public constructor to a Scala class that does NOT require any parameters.

A class (not an object) that doesn't require any parameters has a default public constructor already (my first example).

Actually in Java all classes by default offer a public default constructor

No. Only those classes which have no constructors which take arguments.

remove the "(it won't work for Java classes without a public default constructor either)" because it is wrong

The documentation for Class.newInstance() says

IllegalAccessException - if the class or its nullary constructor is not accessible.

So I am pretty sure it's right. If it does work for Java classes without a public default constructor, this seems to be a major bug in the class loader you use. You can test it with a Java class which looks like this:

public class TestClass implements IRegisterExecutor {
    public TestClass(int dummy) {}

    // some implementation for IRegisterExecutor methods to get it to compile
}
Community
  • 1
  • 1
Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • Thank you for your answer. I don't see in your answer how you add a default public constructor to a Scala class that does NOT require any parameters. The Java version works no problem. Actually in Java all classes by default offer a public default constructor and it seems not to be the case in Scala. Please read carefully my OP, I said it **works** with Java. You are right about being a Scala "object" but I need it to work for a Scala class and it doesn't. – SkyWalker Jul 01 '13 at 12:03
  • 1
    The reason you're encountering the private constructor, I believe, is exactly because you're trying to instantiate the class of a Scala `object`. What you're attempting will work fine for ordinary Scala classes (that have public constructors, which is the default). But Scala needs to control the process of instantiating objects to maintain their singleton nature. – Randall Schulz Jul 01 '13 at 12:52
  • @Alexey If you correct your answer, remove the "(it won't work for Java classes without a public default constructor either)" because it is wrong, I will accept your answer – SkyWalker Jul 01 '13 at 14:59