2012-01-15 28 views
18

Trong Java, tôi nạp lớp bên ngoài (trong file .jar) bằng cách này:Scala - đối tượng Dynamic/lớp bốc

ClassLoader classLoader = new URLClassLoader(new URL[] { 
    new File("module.jar").toURI().toURL()}); 
Class clazz = classLoader.loadClass("my.class.name"); 
Object instance = clazz.newInstance(); 

//check and cast to an interface, then use it 
if (instance instanceof MyInterface) 
    ... 

Và nó hoạt động tốt.

====================

Bây giờ tôi muốn làm điều tương tự trong Scala. Tôi có một trait tên Module (Module.scala):

trait Module { 
    def name: String 
} 

object Module { 
    lazy val ModuleClassName = "my.module.ExModule" 
} 

tôi viết một module mở rộng Module, sau đó biên dịch nó để module.jar:

package my.module 

import Module 

object ExModule extends Module {} 

Sau đó, tôi tải nó bằng mã này:

var classLoader = new URLClassLoader(Array[URL](
    new File("module.jar").toURI.toURL)) 
var clazz = classLoader.loadClass(Module.ModuleClassName) 

Nó hoạt động tốt. Nhưng nếu tôi có thể tạo thể hiện mới, tôi nhận được ngoại lệ này:

java.lang.InstantiationException: my.module.ExModule 

Nếu tôi thử nghiệm nó:

-> luôn luôn trả false.

Bạn có thể giúp tôi về vấn đề này không?

Edited

Tôi đoán đó là vì ExModule là một object (không class). Nhưng khi tôi thay đổi nó thành classclassLoader.loadClass(...) tăng số java.lang.NoClassDefFoundError. Tôi đoán đó là vì ExModule được mở rộng từ một số trait.

Tôi đang bối rối. Có ai giúp tôi không?

Edited

clazz.isInstanceOf[Class[Module]]//or Class[Byte], or Class[_]... 

lợi nhuận true.

+0

Tôi nghĩ rằng bạn đã gần gũi hơn với việc biến nó thành một lớp (khi bạn nhận được ClassNotFoundException). Bạn có chắc chắn rằng khi bạn tham chiếu module.jar bạn đang nhận được đường dẫn phải không? Thực tế là nó được mở rộng từ một đặc điểm không nên tạo ra bất kỳ sự khác biệt nào - ExModule là một lớp (trong trường hợp đó). –

+0

Có, tôi chắc chắn đường dẫn đến 'module.jar' là chính xác. Phương thức 'classLoader.loadClass (...)' hoạt động tốt (trong trường hợp 'ExModule' là' đối tượng'). –

+0

Bạn có thể xem mã bytecode được biên dịch (thông qua javap hoặc tương tự) không? Scalac có thói quen vui nhộn khi thêm $ s và các tên lạ khác xung quanh địa điểm, và có lẽ ExModule của bạn chỉ có một chút tên khác trong phiên bản đã biên dịch. Ngoài ra, bạn có thể yêu cầu scalac để in mã java bằng scala của bạn (Tôi chỉ không nhớ tùy chọn bây giờ). – Rogach

Trả lời

8

Rất tiếc ... Tôi nhận được câu trả lời.

-Học từ:

====================

Tôi đoán theo cách này chỉ là tạm thời trước khi Scala đội cung cấp đúng cách để tải object/class/trait ... từ tệp jar bên ngoài. Hoặc bởi vì tôi không thể tìm ra đúng cách. Nhưng hiện tại điều này giúp tôi giải quyết vấn đề.

var classLoader = new java.net.URLClassLoader(
    Array(new File("module.jar").toURI.toURL), 
    /* 
    * need to specify parent, so we have all class instances 
    * in current context 
    */ 
    this.getClass.getClassLoader) 

/* 
* please note that the suffix "$" is for Scala "object", 
* it's a trick 
*/ 
var clazzExModule = classLoader.loadClass(Module.ModuleClassName + "$") 

/* 
* currently, I don't know how to check if clazzExModule is instance of 
* Class[Module], because clazzExModule.isInstanceOf[Class[_]] always 
* returns true, 
* so I use try/catch 
*/ 
try { 
    //"MODULE$" is a trick, and I'm not sure about "get(null)" 
    var module = clazzExModule.getField("MODULE$").get(null).asInstanceOf[Module] 
} catch { 
    case e: java.lang.ClassCastException => 
    printf(" - %s is not Module\n", clazzExModule) 
} 

Đó là tất cả :-)

Edited

tôi muốn thiết kế tốt hơn ExModule như là một lớp. Sau khi tải nó từ file jar, tôi có thể kiểm tra xem nó như như như:

var clazz = classLoader.loadClass(Module.ModuleClassName) 
if (classOf[Module].isAssignableFrom(clazz)) 
    ... 

Lưu ý:

Bạn không thể làm điều đó theo cách ngược lại:

if (clazz.isAssignableFrom(classOf[Module])) 

Moduletrait/object, isAssignableFrom() sẽ không hoạt động trong trường hợp này.

0
+0

Cảm ơn, tôi đã đọc câu hỏi đó trước khi đăng câu hỏi này. Nhưng tôi vẫn còn bối rối :-(Tôi đang cố gắng ... –

Các vấn đề liên quan