2

私はこの種の問題を抱えています。*.clj ファイルの Eclipse プラグイン (A と表示) に含まれる Clojure コードがあります。AOT コンパイルは必要ありません。ただし、別の Clojure プラグイン B から clojure コードをロードする必要があります。これは、B が A に依存している場合に可能です。Clojure はクラスパスに簡単にアクセスでき、すべてが機能します。しかし、プラグインAをBの拡張としてプラグインしたいのですが、Bに含まれる*.cljファイルからAに含まれるClojureファイルをロードする方法が見つからなかったため、問題があります。クラスパスから* .cljファイルをロードできるClojureの「ロード」関数を使用しますが、この関数はプラグインのコンテンツを表示できませんこのようにプラグインを明示的に開始すると、イベント

 (org.eclipse.core.runtime.Platform/getBundle "A")

ローランの回答に対する反応

ローラン、どうもありがとう!これは非常に興味深いです。ただし、これにより、元の問題よりも難しい問題が解決される可能性があると思います。あなたは完全に素晴らしい Java プラグインから clojure コードを呼び出す方法を説明しました。私は clojure プラグインから clojure コードを呼び出す必要があります。拡張ポイントを作成し、このような clojure 関数を提供することを想像します

<extension point="transforms">
  <function namespace="my.nemaspace" fn="my-transform"/>
</extension>

したがって、IExecutableExtensionFactory には魔法は必要ありません。clojure コードから拡張レジストリーを読み取ることができます。私ができないのは、拡張機能で指定された関数をロードすることです。これは実行可能ですか、それとも何かを誤解しただけですか? clojure.osgi を使用していることに気付きました。このプロジェクトのドキュメントはありますか?

4

2 に答える 2

6

クラスローダーに関してあなたが抱えている問題は予想されることです: Eclipse プラグイン/OSGi バンドルの依存関係が A -> B で、Clojure jar が B からブートストラップされている場合、B から A のリソースを表示できません。正常です。

Eclipse プラグインの依存関係に循環はあり得ないため、クラスローダー階層間に循環はありません。

これは、通常の Eclipse 機構を使用して A から B への拡張機能を作成する場合に直面する問題と同じです。プラグイン B はインターフェースと拡張ポイントを宣言します。次に、プラグイン A はインターフェースを実装し、拡張ポイントへの拡張を宣言できます。この最後の部分により、Eclipse フレームワークはバンドルでいくつかのトリックを実行できます。A が B への拡張を宣言していることを確認し、B で宣言されたインターフェースを実装する A からクラスをインスタンス化し (A は B に依存しているため、これは機能します)、B を提供します。 A からの実装インスタンスも B でインターフェイスを実装しているので問題ありません。

(これが明確かどうかはわかりません)。

とにかく、Clojure で書かれたプラグインに戻りましょう。
Clojure を使用すると、すぐに使用できるように、クラスローダーによって提供される個別の環境はありません。これは、すべてが 1 つの「Clojure 環境」に集約され、clojure jar を埋め込むプラグインのクラスローダー領域に存在するためです。そのため、プラグイン A の起動時に、関連する名前空間を A からロードすることが 1 つの可能性です。その後、それらは適切なタイミングでロードされ、他の Clojure コードで使用できるようになります。もう 1 つの可能性は、Extension Point/Extension 機構を使用することです。Eclipse は、「ファクトリー」を使用して拡張ポイントのインスタンスを作成する方法を提供します。反時計回りでは、この機能を活用し、適切なバンドルから適切な名前空間をロードすることを処理するジェネリック ファクトリ クラス (Java で記述されているため、AOT はありません) を使用します。

ここでは、拡張ポイントを拡張する方法について詳しく説明します。

反時計回りの例:
Eclipse フレームワークには、コンソール コンテンツのハイパーリンク検出機能を提供するための既存の拡張ポイントがあります。この拡張ポイントを反時計回りに拡張して、nrepl ハイパーリンクを追加します。
Java の世界では、IPatternMatchListenerDelegate インターフェイスを実装する自分のクラスを拡張機能で直接宣言する必要があります。
しかし、CCW では、おそらくあなたと同じ理由で、私は AOT を絶対に避けようとしているので、拡張機能で Java クラス名を指定することはできません。または、Java で記述してコンパイルする必要があったでしょう。またはgen-class、Clojure でa を記述してAOT コンパイルします。

代わりに、CCW は plugin.xml の可能性の隠された宝石を活用します。ほとんどすべての場所で、クラス名を指定する必要がある場合、代わりにIExecutableExtensionFactoryのインスタンスを指定できます。このcreate()メソッドは、Eclipse フレームワークによって呼び出され、そのインスタンスを作成します。希望クラス。

これにより、Clojure の世界を呼び出すためのジェネリック クラスを作成することができました。書くべきだったクラス名の代わりに、クラス名ccw.util.GenericExecutableExtensionを使用するだけです。

plugin.xmlから抽出:

<extension point="org.eclipse.ui.console.consolePatternMatchListeners">
<consolePatternMatchListener
   id="ccw.editors.clojure.nREPLHyperlink"
   regex="nrepl://[^':',' ']+:\d+">
    <class class="ccw.util.GenericExecutableExtension">
       <parameter
             name="factory"
             value="ccw.editors.clojure.nrepl-hyperlink/factory">
       </parameter>
    </class>
</consolePatternMatchListener>

属性と、要素classを介してファクトリにパラメータを与える方法に注意してください(ファクトリは、パラメータで初期化できるようにインターフェイスIExecutableExtensionを実装する必要があります)。parameter

ccw.editors.clojure.nrepl-hyperlink最後に、 namespaceでは、関数ファクトリはかなり単純で、make関数を呼び出すだけであることがわかります。

(defn make []
  (let [state (atom nil)]
    (reify org.eclipse.ui.console.IPatternMatchListenerDelegate
      (connect [this console]  (dosync (reset! state console)))
      (disconnect [this]       (reset! state nil))
      (matchFound [this event] (match-found event @state)))))

(defn factory "plugin.xml hook" [ _ ] (make))

これは例として示していることに注意してください。反時計回りの関連コードは、「すぐに使用できる」独立したライブラリとしてリリースする準備ができていません。
それでも、独自のソリューションを展開できるはずです (頭の中にすべてのピースが配置されていれば、非常に簡単です)。

それが役立つことを願って、

-- ローラン

于 2012-10-02T19:54:50.760 に答える
0

別の解決策が思い浮かびました。以前の回答で述べたことにもかかわらず、Eclipse では、クラスローダー間に循環的な依存関係を作成することが可能です。

Eclipse 関係者は、これを導入して、特定のタイプのライブラリ (log4j など) が OSGi 環境 (Eclipse が基づいている環境) で動作できるようにする必要がありました。

Eclipse-BuddyPolicyこれには、メカニズム (サードパーティ ライブラリとクラスローディング)を活用する必要があります。

とても簡単です: プラグイン B にプラグイン A のすべてのクラスとリソースを表示させたい場合は、これをプラグイン B のMETA-INF/MANIFEST.MFファイルに追加するだけです:

Eclipse-BuddyPolicy: dependent

上記の行は、プラグイン B のクラスローダーが、その依存クラスローダーがアクセスできるものにアクセスできることを示しています。

A と B という名前のプラグインのサンプル セットを作成しました。B には 2 つのコマンドがあります (トップ メニューに表示されます)。最初のコマンドは、B で clojure コードを呼び出して、ハード コードされた "hello" 文字列にテキスト変換を適用します。プラグイン A からの新しいテキスト変換。最初のコマンドを再度呼び出すと、B からの変換と A からの変換を適用した結果が表示されます。

あなたの場合、結局のところ、Eclipse 拡張ポイント/拡張メカニズムを使用する必要さえないかもしれません。それはすべて、プラグイン B がプラグイン A の関連情報をどのように「発見」するかによって異なります。

これを実際に示している github リポジトリ: https://github.com/laurentpetit/stackoverflow-12689605

HTH、

-- ローラン

于 2012-10-06T23:36:36.113 に答える