[英]When multiple versions of a class are made available by different class loaders, how can I reference a particular one?
此問題源於IntelliJ GUI設計器,該設計器似乎在包含其自己的舊版本MigLayout
的環境中加載自定義表單組件。
如果我創建一個使用MigLayout
的自定義組件:
import net.miginfocom.layout.CC;
import net.miginfocom.layout.LC;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
public class ComponentUsingMigLayout extends JPanel {
public ComponentUsingMigLayout() {
try {
setLayout(new MigLayout(new LC().insets("20")));
add(new JButton("Hello"), new CC().cell(0, 0));
}
catch (Throwable t) {
JOptionPane.showMessageDialog(null, t.toString());
}
}
}
然后創建一個GUI窗體,執行“向組件添加組件”,然后選擇ComponentUsingMigLayout
,我看到帶有java.lang.NoSuchMethodError: net.miginfocom.layout.CC.cell([I)Lnet/miginfocom/layout/CC
消息對話框java.lang.NoSuchMethodError: net.miginfocom.layout.CC.cell([I)Lnet/miginfocom/layout/CC
。
我猜這是因為IntelliJ加載了自己的MigLayout
版本,該版本可用於表單組件,而這是一個缺少可變參數cell()
方法的舊版本。 我知道,由於對"com.miglayout" % "miglayout-core" % "4.2"
的依賴,因此MigLayout的較新版本也應可用於運行時。
這是一個完整的示例,其中包含IDEA項目文件 。
有沒有一種方法可以強制使用"com.miglayout" % "miglayout-core" % "4.2"
?
解決方案是檢測GUI設計器正在加載類的情況,並剖析類加載器以刪除父類:
package guidesignermiglayout;
import javax.swing.*;
import java.awt.*;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
@SuppressWarnings({"unchecked", "ToArrayCallWithZeroLengthArrayArgument"})
public class ComponentUsingMigLayout extends JPanel {
public ComponentUsingMigLayout() {
try {
ClassLoader cl = getClass().getClassLoader();
ClassLoader localCL;
if (cl.getClass().getName().contains("DesignTimeClassLoader")) {
localCL = new URLClassLoader(((List<URL>) cl.getClass().getMethod("getUrls").invoke(cl)).toArray(new URL[]{}));
}
else {
localCL = cl;
}
Class migLayout = localCL.loadClass("net.miginfocom.swing.MigLayout");
Class lc = localCL.loadClass("net.miginfocom.layout.LC");
Method insets = lc.getDeclaredMethod("insets", String.class);
Class cc = localCL.loadClass("net.miginfocom.layout.CC");
Method cell = cc.getDeclaredMethod("cell", int[].class);
setLayout((LayoutManager) migLayout.getConstructor(lc).newInstance(
insets.invoke(lc.newInstance(), "20")
));
add(new JButton("Hello"), cell.invoke(cc.newInstance(), new Object[]{new int[]{0, 0}}));
}
catch (Throwable t) {
JOptionPane.showMessageDialog(null, t.toString());
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.