clojure: ExceptionInInitializerError в пространстве имен. <init>загрузка из пути к классам не по умолчанию - PullRequest
1 голос
/ 22 марта 2012

При попытке загрузить скомпилированный AOT класс из пути к классам не по умолчанию я получаю следующее исключение:

Traceback (innermost last):
  File "test.jy", line 10, in ?
        at clojure.lang.Namespace.<init>(Namespace.java:34)
        at clojure.lang.Namespace.findOrCreate(Namespace.java:176)
        at clojure.lang.Var.internPrivate(Var.java:149)
        at aot_demo.JavaClass.<clinit>(Unknown Source)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:247)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
java.lang.ExceptionInInitializerError: java.lang.ExceptionInInitializerError

Я могу воспроизвести это следующим тривиальным project.clj:

(defproject aot-demo "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.3.0"]]
  :aot [aot-demo.core])

... и src/aot_demo/core.clj определены следующим образом:

(ns aot-demo.core
  (:gen-class
    :name aot_demo.JavaClass
    :methods [#^{:static true} [lower [java.lang.String] java.lang.String]]))

(defn -lower [str] (.toLowerCase str))

Тогда для запуска ошибки достаточно следующего Jython-скрипта:

#!/usr/bin/jython
import java.lang.Class
import java.net.URLClassLoader
import java.net.URL
import os

customLoader = java.net.URLClassLoader(
    [java.net.URL('file://%s/target/aot-demo-0.1.0-SNAPSHOT-standalone.jar'
                  % (os.getcwd()))])

java.lang.Class.forName('aot_demo.JavaClass', True, customLoader)

Однако исключение не возникает, если тестовый скрипт запускается с uberjar, уже находящимся в переменной CLASSPATH.

Что здесь происходит? Я пытаюсь написать плагин для базы данных BaseX в Clojure; приведенное выше точно показывает, как работает их механизм загрузки плагинов с целью обеспечения SSCE для этой проблемы.

1 Ответ

0 голосов
/ 22 марта 2012

Механизм загрузки плагинов, используемый BaseX, должен быть расширен для изменения загрузчика классов текущего потока. Для данного примера кода (в Jython) это будет выглядеть примерно так:

currentThread = java.lang.Thread.currentThread()
oldLoader = currentThread.getContextClassLoader()

currentThread.setContextClassLoader(customLoader)
try:
    cls = java.lang.Class.forName('aot_demo.JavaClass', True, customLoader)
finally:
    currentThread.setContextClassLoader(oldLoader)
...