reflectでクラスブラウザ
java.lang.reflectを使って、クラスブラウザを書いてみた。
■ソースコード
次のようなコードを書いてみた。
クラスパスのJarファイルを検索し、クラスの木構造を構築する。
文字列で順序付けした木構造を得るため、DefaultTreeModelのTreeNodeにはインナークラスSortedTreeNodeを用いている。
package test; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.TreeSet; import java.util.zip.ZipFile; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTable; import javax.swing.JTree; import javax.swing.table.DefaultTableModel; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; public class JClassBrowserPanel extends JPanel { /** * */ private static final long serialVersionUID = 1L; private Map<String,DefaultMutableTreeNode> map =new HashMap<String,DefaultMutableTreeNode>(); private String classpath = System.getProperty("java.class.path"); private String homepath = System.getProperty("java.home"); private String pathsep = File.pathSeparator; private JTree tree; private JTable cons,field,method; private JPopupMenu pop; private DefaultTreeModel model; private SortedTreeNode root; public JClassBrowserPanel(){ super(new BorderLayout()); root=new SortedTreeNode("root"); model=new DefaultTreeModel(root); initPanel(); Runnable r=new Runnable(){ public void run(){ parse(); Runnable rr=new Runnable(){ public void run(){ TreeNode last=root.getLastChild(); tree.expandPath(new TreePath(new TreeNode[]{root,last})); } }; javax.swing.SwingUtilities.invokeLater(rr); } }; new Thread(r).start(); } private void initPanel(){ JSplitPane sp=new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); tree=new JTree(root); tree.addMouseListener(new TreeMouse()); tree.setModel(model); JScrollPane sc=new JScrollPane(tree); sp.setLeftComponent(sc); JPanel panel=new JPanel(new BorderLayout()); JSplitPane spl0=new JSplitPane(JSplitPane.VERTICAL_SPLIT); JSplitPane spl1=new JSplitPane(JSplitPane.VERTICAL_SPLIT); panel.add(spl0,BorderLayout.CENTER); spl0.setRightComponent(spl1); JPanel u=new JPanel(new BorderLayout()); cons=new JTable(new TModel()); ((DefaultTableModel)cons.getModel()).setColumnCount(1); ((DefaultTableModel)cons.getModel()).setRowCount(0); ((DefaultTableModel)cons.getModel()).setColumnIdentifiers(new String[]{"Constractor"}); JScrollPane sc0=new JScrollPane(cons); u.add(sc0,BorderLayout.CENTER); spl0.setLeftComponent(u); JPanel m=new JPanel(new BorderLayout()); field=new JTable(new TModel()); ((DefaultTableModel)field.getModel()).setColumnCount(1); ((DefaultTableModel)field.getModel()).setRowCount(0); ((DefaultTableModel)field.getModel()).setColumnIdentifiers(new String[]{"Field"}); JScrollPane sc1=new JScrollPane(field); m.add(sc1,BorderLayout.CENTER); spl1.setLeftComponent(m); JPanel d=new JPanel(new BorderLayout()); method=new JTable(new TModel()); ((DefaultTableModel)method.getModel()).setColumnCount(1); ((DefaultTableModel)method.getModel()).setRowCount(0); ((DefaultTableModel)method.getModel()).setColumnIdentifiers(new String[]{"Method"}); JScrollPane sc2=new JScrollPane(method); d.add(sc2,BorderLayout.CENTER); spl1.setRightComponent(d); sp.setRightComponent(panel); add(sp,BorderLayout.CENTER); sp.setDividerSize(3); sp.setDividerLocation(200); spl0.setDividerSize(3); spl0.setDividerLocation(100); spl1.setDividerSize(3); spl1.setDividerLocation(100); pop=new JPopupMenu(); JMenuItem it=new JMenuItem("send"); it.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent arg0) { TreePath p=tree.getSelectionPath(); if(p==null)return; } }); pop.add(it); } private void parse(){ StringTokenizer tk = new StringTokenizer(classpath, pathsep); while (tk.hasMoreTokens()) { File file = new File(tk.nextToken()); if (file.exists()) { if(file.isDirectory()){ searchDir(file); }else{ try{ searchZip(new ZipFile(file)); }catch(IOException ie){} } } } tk = new StringTokenizer(homepath, pathsep); while (tk.hasMoreTokens()) { File file = new File(tk.nextToken()); if (file.exists()) { if(file.isDirectory()){ searchDir(file); }else{ try{ searchZip(new ZipFile(file)); }catch(IOException ie){} } } } } private void searchDir(File dir) { File[] f=dir.listFiles(); for(int i=0;i<f.length;i++){ if(f[i].isDirectory()){ searchDir(f[i]); }else{ try{ searchZip(new ZipFile(f[i])); }catch(IOException ie){} } } } private void searchZip(ZipFile zip) { Enumeration<?> e=zip.entries(); while(e.hasMoreElements()){ String name=e.nextElement().toString(); if(name.contains(".class")){ String[] str=name.split("/"); if(str[str.length-1].indexOf("$")!=-1)continue; regedit(str); } } } private void regedit(String[] path){ DefaultMutableTreeNode parent=root; String tmp=null; for(int i=0;i<path.length;i++){ if(tmp==null){ tmp=path[i]; }else{ tmp=tmp+"."+path[i]; } DefaultMutableTreeNode m=map.get(tmp); if(m==null){ DefaultMutableTreeNode x=new SortedTreeNode(path[i]); map.put(tmp,x); model.insertNodeInto(x, parent, 0); parent=x; }else{ parent=m; } } } private String getClassName(TreePath p){ int n=p.getPathCount(); String str=""; for(int i=1;i<n;i++){ String ss=((DefaultMutableTreeNode)p.getPathComponent(i)).getUserObject().toString(); if(i==1){ str=ss; }else{ str=str+"."+ss; } } str=str.replace(".class",""); return str; } private class SortedTreeNode extends DefaultMutableTreeNode{ /** * */ private static final long serialVersionUID = 1L; private Set<String> set; public SortedTreeNode(Object obj){ super(obj); set=new TreeSet<String>(); } @Override public void add(MutableTreeNode arg0) { set.add(arg0.toString()); int id=index(arg0.toString()); super.insert(arg0, id); } @Override public void insert(MutableTreeNode arg0, int arg1) { this.add(arg0); } @Override public void remove(int arg0) { super.remove(arg0); } @Override public void remove(MutableTreeNode arg0) { super.remove(arg0); set.remove(arg0.toString()); } @Override public void removeAllChildren() { super.removeAllChildren(); set.clear(); } private int index(String arg){ String[] st=set.toArray(new String[set.size()]); for(int i=0;i<st.length;i++){ if(st[i].equals(arg))return i; } return -1; } } private class TreeMouse implements MouseListener{ public void mouseClicked(MouseEvent arg0) { switch(arg0.getButton()){ case MouseEvent.BUTTON1: TreePath p=tree.getSelectionPath(); if(p==null)return; DefaultMutableTreeNode tn=(DefaultMutableTreeNode)p.getLastPathComponent(); if(tn.isLeaf()){ String name=getClassName(p); try{ Class<?> c=Class.forName(name); Constructor<?>[] cn=c.getConstructors(); String[] names=new String[cn.length]; for(int i=0;i<cn.length;i++){ names[i]=cn[i].getName()+"("; Class<?>[] cc=cn[i].getParameterTypes(); for(int j=0;j<cc.length;j++){ if(j==0){ names[i]=names[i]+cc[j].getName(); }else{ names[i]=names[i]+","+cc[j].getName(); } } names[i]=names[i]+")"; } Arrays.sort(names); DefaultTableModel tm=(DefaultTableModel)cons.getModel(); tm.setRowCount(cn.length); for(int i=0;i<cn.length;i++){ tm.setValueAt(names[i], i, 0); } Field[] fn=c.getFields(); names=new String[fn.length]; for(int i=0;i<fn.length;i++)names[i]=fn[i].getName()+" as "+fn[i].getType(); Arrays.sort(names); tm=(DefaultTableModel)field.getModel(); tm.setRowCount(fn.length); for(int i=0;i<fn.length;i++){ tm.setValueAt(names[i], i, 0); } Method[] mn=c.getMethods(); names=new String[mn.length]; for(int i=0;i<mn.length;i++){ names[i]=mn[i].getName()+"("; Class<?>[] cc=mn[i].getParameterTypes(); for(int j=0;j<cc.length;j++){ if(j==0){ names[i]=names[i]+cc[j].getName(); }else{ names[i]=names[i]+","+cc[j].getName(); } } names[i]=names[i]+")"; } Arrays.sort(names); tm=(DefaultTableModel)method.getModel(); tm.setRowCount(mn.length); for(int i=0;i<mn.length;i++){ tm.setValueAt(names[i], i, 0); } }catch(ClassNotFoundException ce){} } break; } } public void mouseEntered(MouseEvent arg0) {} public void mouseExited(MouseEvent arg0) {} public void mousePressed(MouseEvent arg0) {} public void mouseReleased(MouseEvent arg0) {} } private class TModel extends DefaultTableModel{ /** * */ private static final long serialVersionUID = 1L; @Override public boolean isCellEditable(int arg0, int arg1) { return false; } } public static void main(String[] args){ JFrame f=new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.getContentPane().setLayout(new BorderLayout()); JClassBrowserPanel cb=new JClassBrowserPanel(); f.getContentPane().add(cb,BorderLayout.CENTER); f.setSize(640, 400); f.setTitle("Test"); f.setVisible(true); } }