简体   繁体   English

使用反射Java的`newInstance`实例化Scala类

[英]instantiating a Scala class using reflection Java's `newInstance`

For some special use-case I have a small utility to load Java classes from jars using a dynamic class loader DynamicClassLoader . 对于某些特殊用例,我有一个小的实用程序,可以使用动态类加载器DynamicClassLoader从jar中加载Java类。 This works fine for Java classes contained in jars. 这对于jars中包含的Java类很好用。 Loading Scala classes from a jar also works without problems. 从jar加载Scala类也可以正常工作。 However, instantiating the loaded Scala class leads to the following exception. 但是,实例化已加载的Scala类会导致以下异常。 It looks like the Scala class has private default constructor? 看起来Scala类具有私有的默认构造函数? Note the compiled Scala class name ending with $ 请注意,已编译的Scala类名称以$结尾

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? 任何想法如何解决?

Obviously, you need to make the default constructor public (it won't work for Java classes without a public default constructor either). 显然,您需要将默认构造函数设为公共(没有公共默认构造函数的Java类也无法使用)。 Eg 例如

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 $ 请注意,已编译的Scala类名称以$结尾

it seems like you are actually trying to instantiate a Scala object : 看来您实际上是在尝试实例化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. 我没有在您的答案中看到如何将默认的公共构造函数添加到不需要任何参数的Scala类中。

A class ( not an object ) that doesn't require any parameters has a default public constructor already (my first example). 不需要任何参数的class不是 object )已经具有默认的公共构造函数(我的第一个示例)。

Actually in Java all classes by default offer a public default constructor 实际上,在Java中,默认情况下所有类都提供一个公共默认构造函数

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 删除“((如果没有公共默认构造函数,它也将不适用于Java类)”,因为它是错误的

The documentation for Class.newInstance() says Class.newInstance()文档

IllegalAccessException - if the class or its nullary constructor is not accessible. IllegalAccessException如果该类或其无效构造函数不可访问。

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. 如果它确实适用于没有公共默认构造函数的Java类,则这似乎是您使用的类加载器中的主要错误。 You can test it with a Java class which looks like this: 您可以使用如下所示的Java类对其进行测试:

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

    // some implementation for IRegisterExecutor methods to get it to compile
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM