此问题源于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
。
我猜这是因为IntelliJ加载了自己的MigLayout
版本,可用于表单组件,这是一个缺少可变参数cell()
方法的旧版本。我知道由于依赖"com.miglayout" % "miglayout-core" % "4.2"
,运行时也应该有更新版本的MigLayout。
这是complete example including IDEA project files。
有没有办法强制使用"com.miglayout" % "miglayout-core" % "4.2"
?
答案 0 :(得分:0)
解决方案是检测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());
}
}
}