お仕事の話ですが、次のような要求をJava Parserを用いて実現したので、メモとして残しておきます。
- javaファイルに定義されているクラスとメソッドを一覧化したい
- あわせてそのメソッドが呼び出しているメソッドをメソッドごとに一覧化したい
以下はjava.util.Properties.javaを対象のソースコードとして、上記の要求を満たすサンプルプログラムです。なお、Properties.javaはopenjdk-jdk11より拝借しています。
public static void main(String[] args) throws IOException {
CompilationUnit compilationUnit = StaticJavaParser.parse(Paths.get("Properties.java"));
compilationUnit.accept(new ClassOrInterfaceDeclarationVisitor(), null);
}
static class ClassOrInterfaceDeclarationVisitor extends VoidVisitorAdapter<Void> {
@Override
public void visit(ClassOrInterfaceDeclaration n, Void arg) {
System.out.println(n.getFullyQualifiedName().get());
for (MethodDeclaration md : n.getMethods()) {
System.out.println("\t" + md.getDeclarationAsString(true, true, true));
md.accept(new MethodCallExprVisitor(), null);
}
super.visit(n, arg);
}
}
static class MethodCallExprVisitor extends VoidVisitorAdapter<Void> {
@Override
public void visit(MethodCallExpr n, Void arg) {
System.out.println("\t\t" + n);
super.visit(n, arg);
}
}
これを実行すると、以下のような結果がコンソールに出力されるはずです。
長いのでおりたたみ
java.util.Properties
public synchronized Object setProperty(String key, String value)
put(key, value)
public synchronized void load(Reader reader) throws IOException
Objects.requireNonNull(reader, "reader parameter is null")
load0(new LineReader(reader))
public synchronized void load(InputStream inStream) throws IOException
Objects.requireNonNull(inStream, "inStream parameter is null")
load0(new LineReader(inStream))
private void load0(LineReader lr) throws IOException
loadConvert(lr.lineBuf, 0, keyLen, convtBuf)
loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf)
put(key, value)
lr.readLine()
private String loadConvert(char[] in, int off, int len, char[] convtBuf)
private String saveConvert(String theString, boolean escapeSpace, boolean escapeUnicode)
theString.length()
theString.charAt(x)
outBuffer.append('\\')
outBuffer.append('\\')
outBuffer.append(aChar)
outBuffer.append('\\')
outBuffer.append(' ')
outBuffer.append('\\')
outBuffer.append('t')
outBuffer.append('\\')
outBuffer.append('n')
outBuffer.append('\\')
outBuffer.append('r')
outBuffer.append('\\')
outBuffer.append('f')
outBuffer.append('\\')
outBuffer.append(aChar)
outBuffer.append(aChar)
outBuffer.append('\\')
outBuffer.append('u')
outBuffer.append(toHex((aChar >> 12) & 0xF))
toHex((aChar >> 12) & 0xF)
outBuffer.append(toHex((aChar >> 8) & 0xF))
toHex((aChar >> 8) & 0xF)
outBuffer.append(toHex((aChar >> 4) & 0xF))
toHex((aChar >> 4) & 0xF)
outBuffer.append(toHex(aChar & 0xF))
toHex(aChar & 0xF)
outBuffer.toString()
private static void writeComments(BufferedWriter bw, String comments) throws IOException
bw.write("#")
comments.length()
comments.charAt(current)
bw.write(comments.substring(last, current))
comments.substring(last, current)
bw.newLine()
comments.charAt(current + 1)
comments.charAt(current + 1)
comments.charAt(current + 1)
bw.write("#")
toHex((c >> 12) & 0xf)
toHex((c >> 8) & 0xf)
toHex((c >> 4) & 0xf)
toHex(c & 0xf)
bw.write(new String(uu))
bw.write(comments.substring(last, current))
comments.substring(last, current)
bw.newLine()
public void save(OutputStream out, String comments)
store(out, comments)
public void store(Writer writer, String comments) throws IOException
store0((writer instanceof BufferedWriter) ? (BufferedWriter) writer : new BufferedWriter(writer), comments, false)
public void store(OutputStream out, String comments) throws IOException
store0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")), comments, true)
private void store0(BufferedWriter bw, String comments, boolean escUnicode) throws IOException
writeComments(bw, comments)
bw.write("#" + new Date().toString())
new Date().toString()
bw.newLine()
e.getKey()
e.getValue()
saveConvert(key, true, escUnicode)
saveConvert(val, false, escUnicode)
bw.write(key + "=" + val)
bw.newLine()
entrySet()
bw.flush()
public synchronized void loadFromXML(InputStream in) throws IOException, InvalidPropertiesFormatException
Objects.requireNonNull(in)
handler.load(this, in)
in.close()
public void storeToXML(OutputStream os, String comment) throws IOException
storeToXML(os, comment, "UTF-8")
public void storeToXML(OutputStream os, String comment, String encoding) throws IOException
Objects.requireNonNull(os)
Objects.requireNonNull(encoding)
Charset.forName(encoding)
storeToXML(os, comment, charset)
public void storeToXML(OutputStream os, String comment, Charset charset) throws IOException
Objects.requireNonNull(os, "OutputStream")
Objects.requireNonNull(charset, "Charset")
handler.store(this, os, comment, charset)
public String getProperty(String key)
map.get(key)
defaults.getProperty(key)
public String getProperty(String key, String defaultValue)
getProperty(key)
public Enumeration<?> propertyNames()
enumerate(h)
h.keys()
public Set<String> stringPropertyNames()
enumerateStringProperties(h)
Collections.unmodifiableSet(h.keySet())
h.keySet()
public void list(PrintStream out)
out.println("-- listing properties --")
enumerate(h)
e.getKey()
e.getValue()
val.length()
val.substring(0, 37)
out.println(key + "=" + val)
h.entrySet()
public void list(PrintWriter out)
out.println("-- listing properties --")
enumerate(h)
e.getKey()
e.getValue()
val.length()
val.substring(0, 37)
out.println(key + "=" + val)
h.entrySet()
private void enumerate(Map<String, Object> h)
defaults.enumerate(h)
e.getKey()
h.put(key, e.getValue())
e.getValue()
entrySet()
private void enumerateStringProperties(Map<String, String> h)
defaults.enumerateStringProperties(h)
e.getKey()
e.getValue()
h.put((String) k, (String) v)
entrySet()
private static char toHex(int nibble)
public int size()
map.size()
public boolean isEmpty()
map.isEmpty()
public Enumeration<Object> keys()
Collections.enumeration(map.keySet())
map.keySet()
public Enumeration<Object> elements()
Collections.enumeration(map.values())
map.values()
public boolean contains(Object value)
map.contains(value)
public boolean containsValue(Object value)
map.containsValue(value)
public boolean containsKey(Object key)
map.containsKey(key)
public Object get(Object key)
map.get(key)
public synchronized Object put(Object key, Object value)
map.put(key, value)
public synchronized Object remove(Object key)
map.remove(key)
public synchronized void putAll(Map<?, ?> t)
map.putAll(t)
public synchronized void clear()
map.clear()
public synchronized String toString()
map.toString()
public Set<Object> keySet()
Collections.synchronizedSet(map.keySet(), this)
map.keySet()
public Collection<Object> values()
Collections.synchronizedCollection(map.values(), this)
map.values()
public Set<Map.Entry<Object, Object>> entrySet()
Collections.synchronizedSet(new EntrySet(map.entrySet()), this)
map.entrySet()
public synchronized boolean equals(Object o)
map.equals(o)
public synchronized int hashCode()
map.hashCode()
public Object getOrDefault(Object key, Object defaultValue)
map.getOrDefault(key, defaultValue)
public synchronized void forEach(BiConsumer<? super Object, ? super Object> action)
map.forEach(action)
public synchronized void replaceAll(BiFunction<? super Object, ? super Object, ?> function)
map.replaceAll(function)
public synchronized Object putIfAbsent(Object key, Object value)
map.putIfAbsent(key, value)
public synchronized boolean remove(Object key, Object value)
map.remove(key, value)
public synchronized boolean replace(Object key, Object oldValue, Object newValue)
map.replace(key, oldValue, newValue)
public synchronized Object replace(Object key, Object value)
map.replace(key, value)
public synchronized Object computeIfAbsent(Object key, Function<? super Object, ?> mappingFunction)
map.computeIfAbsent(key, mappingFunction)
public synchronized Object computeIfPresent(Object key, BiFunction<? super Object, ? super Object, ?> remappingFunction)
map.computeIfPresent(key, remappingFunction)
public synchronized Object compute(Object key, BiFunction<? super Object, ? super Object, ?> remappingFunction)
map.compute(key, remappingFunction)
public synchronized Object merge(Object key, Object value, BiFunction<? super Object, ? super Object, ?> remappingFunction)
map.merge(key, value, remappingFunction)
protected void rehash()
public synchronized Object clone()
cloneHashtable()
void writeHashtable(ObjectOutputStream s) throws IOException
map.size()
entryStack.add(entry.getValue())
entry.getValue()
entryStack.add(entry.getKey())
entry.getKey()
map.entrySet()
entryStack.size()
defaultWriteHashtable(s, length, loadFactor)
s.writeInt(length)
s.writeInt(count)
s.writeObject(entryStack.get(i))
entryStack.get(i)
entryStack.size()
void readHashtable(ObjectInputStream s) throws IOException, ClassNotFoundException
s.defaultReadObject()
s.readInt()
s.readInt()
SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Map.Entry[].class, HashMap.tableSizeFor((int) (elements / 0.75)))
HashMap.tableSizeFor((int) (elements / 0.75))
SharedSecrets.getJavaObjectInputStreamAccess()
s.readObject()
s.readObject()
map.put(key, value)
java.util.Properties.LineReader
int readLine() throws IOException
inStream.read(inByteBuf)
reader.read(inCharBuf)
inStream.read(inByteBuf)
reader.read(inCharBuf)
System.arraycopy(lineBuf, 0, buf, 0, lineBuf.length)
java.util.Properties.EntrySet
public int size()
entrySet.size()
public boolean isEmpty()
entrySet.isEmpty()
public boolean contains(Object o)
entrySet.contains(o)
public Object[] toArray()
entrySet.toArray()
public T[] toArray(T[] a)
entrySet.toArray(a)
public void clear()
entrySet.clear()
public boolean remove(Object o)
entrySet.remove(o)
public boolean add(Map.Entry<Object, Object> e)
public boolean addAll(Collection<? extends Map.Entry<Object, Object>> c)
public boolean containsAll(Collection<?> c)
entrySet.containsAll(c)
public boolean removeAll(Collection<?> c)
entrySet.removeAll(c)
public boolean retainAll(Collection<?> c)
entrySet.retainAll(c)
public Iterator<Map.Entry<Object, Object>> iterator()
entrySet.iterator()
サンプリングでチェックしてみましょう。storeToXMLメソッドの実装は以下の通りです。
public void storeToXML(OutputStream os, String comment, String encoding)
throws IOException {
Objects.requireNonNull(os);
Objects.requireNonNull(encoding);
try {
Charset charset = Charset.forName(encoding);
storeToXML(os, comment, charset);
} catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
throw new UnsupportedEncodingException(encoding);
}
}
これに対応する解析結果は以下の通りです。
public void storeToXML(OutputStream os, String comment, String encoding) throws IOException
Objects.requireNonNull(os)
Objects.requireNonNull(encoding)
Charset.forName(encoding)
storeToXML(os, comment, charset)
ただしく解析できていそうですね。
環境 : pom.xml抜粋
<properties>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-core</artifactId>
<version>3.25.4</version>
</dependency>
</dependencies>