JDTを使ってメソッドの呼び出し元を検索する方法
備忘録として。 eclipseとjdtを使ったメソッド呼び出し元検索のサンプルコード。
import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.equinox.app.IApplication; import org.eclipse.equinox.app.IApplicationContext; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.search.IJavaSearchScope; import org.eclipse.jdt.core.search.SearchEngine; import org.eclipse.jdt.internal.corext.callhierarchy.CallHierarchy; import org.eclipse.jdt.internal.corext.callhierarchy.MethodWrapper; public class Application implements IApplication { public Object start(IApplicationContext context) throws Exception { String projectName = "sample"; String fqcn = "pkg.ClassA"; String methodName = "methodA"; IType type = findType(projectName, fqcn); IMember[] members = findMethod(type, methodName); for (IMember m : members) { CallTracer tracer = new CallTracer(m); traceCaller(tracer); tracer.trace(); // tracer.traceSimple(); } return IApplication.EXIT_OK; } private void traceCaller(CallTracer tracer) { IMember member = tracer.getTarget(); CallerUtil util = new CallerUtil(); Set<IMethod> methods = util.getCallers(member); for (Iterator<IMethod> ite = methods.iterator(); ite.hasNext();) { IMethod next = ite.next(); CallTracer c = new CallTracer(next); tracer.addCaller(c); traceCaller(c); } } private IMethod[] findMethod(IType type, String methodName) throws JavaModelException { IMethod[] methods = type.getMethods(); List<IMethod> result = new ArrayList<IMethod>(); for (IMethod method : methods) { if (method.getElementName().equals(methodName)) { result.add(method); } } return result.toArray(new IMethod[result.size()]); } private IType findType(String projectName, String fullName) throws JavaModelException { IJavaProject jp = JavaCore.create(ResourcesPlugin.getWorkspace().getRoot().getProject(projectName)); return jp.findType(fullName); } @Override public void stop() { // TODO Auto-generated method stub } class CallerUtil { public HashSet<IMethod> getCallers(IMember member) { CallHierarchy callHierarchy = CallHierarchy.getDefault(); IJavaSearchScope scope = SearchEngine.createWorkspaceScope(); callHierarchy.setSearchScope(scope); IMember[] members = { member }; MethodWrapper[] methodWrappers = callHierarchy.getCallerRoots(members); HashSet<IMethod> result = new HashSet<IMethod>(); for (MethodWrapper mw : methodWrappers) { MethodWrapper[] calls = mw.getCalls(new NullProgressMonitor()); result.addAll(getMethods(calls)); } return result; } private HashSet<IMethod> getMethods(MethodWrapper[] methodWrappers) { HashSet<IMethod> result = new HashSet<IMethod>(); for (MethodWrapper mw : methodWrappers) { IMethod method = toMethod(mw); if (method != null) { result.add(method); } } return result; } private IMethod toMethod(MethodWrapper methodWrappers) { IMember member = methodWrappers.getMember(); if (member.getElementType() == IJavaElement.METHOD) { return (IMethod) methodWrappers.getMember(); } else { System.out.println("IGNORE:" + member.toString()); } return null; } } class CallTracer { private IMember target; private List<CallTracer> callers; public CallTracer(IMember member) { target = member; callers = new ArrayList<CallTracer>(); } public void addCaller(CallTracer c) { callers.add(c); } public IMember getTarget() { return target; } public void trace() { trace(0); } private void trace(int idt) { printTrace(idt); for (CallTracer tracer : callers) { idt++; tracer.trace(idt); } } public void traceSimple() { traceSimple(true, 0); } public void traceSimple(boolean pltFlg, int idt) { if (pltFlg) { printTrace(idt); idt++; } if (callers.isEmpty()) { printTrace(idt); } else { for (CallTracer tracer : callers) { tracer.traceSimple(false, idt); } } } private void printTrace(int idt) { System.out.println(getIdt(idt) + " class:" + target.getParent().getElementName()); System.out.println(getIdt(idt) + "method:" + target.getElementName()); } private String getIdt(int idt) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < idt; i++) { sb.append("\t"); } return sb.toString(); } } }
Ruby on Railsの勉強 -RailsTutorial 第2章-
第2章Toyアプリケーション
第2章ではscaffoldというジェネレータの説明と、それを使用したRailsのWebプログラミングの概要が学べる。
Railsアプリケーションの作成
1章と同じようにRailsアプリケーションの作成から。
rails new アプリケーション名(任意)
Gemfile
チュートリアルの通り適当にGemfileを修正してgemのインストールを実施。
bundle install --without production
Gemfileには各環境(開発環境、本番環境等)毎にインストールするライブラリを分けることができ、--without
オプションで指定したグループのライブラリをスキップすることが可能。
ルーティング
Railsアプリケーションが受け付けるリクエストを定義。また、リクエストに対応するコントローラのアクションに紐づけるための定義ファイル。
“コントローラ名”#“アクション名"のルールで任意のコントローラ、アクションへの紐付けが可能になる。
# config/routes.rb Rails.application.routes.draw do # コンテキストルートへのリクエストは ApplicationController.main が処理を受け付ける root 'application#main' # '/about'へのリクエストは ApplicationController.about が処理を受け付ける get '/about', to: 'application#about' end
コントローラ
その他の通りコントローラ。上記ルーティングを例にすると次のようになる。
# app/controllers/application_controller.rb class ApplicationController < ActionController::Base def main end def about end end
Git / Heroku
その後はGit(Bitbucket)へコミットしてから、Herokuへデプロイして準備完了。
# Gitにコミット git commit -am "add 'hello, world'" # Herokuに新規アプリケーションを作成してアプリをデプロイ heroku create git push heroku master
rails generate
rails generate
を使用するとモデルやコントローラ等、様々なテンプレートを自動生成することができる。チュートリアルではrails generate scaffold
を使用した。
scaffold
を使用すると、登録、編集、削除、一覧表示を行うために必要なリソース(コントローラ、モデル、ビュー、マイグレーション等の全部入り)が自動生成される。
# Userテーブルに対して登録、編集、削除、一覧ができるアプリケーションテンプレートを作成 rails generate scaffold User name:String age:integer
rails db:migrate
具体的な仕組みはまだ理解できていないけども、マイグレーションファイルに基づいてDBの構築まで実施してくれる。
# rails generate scaffoldでテンプレート作成実施 rails generate scaffold User name:String age:integer # データベースのマイグレーションを行う rails db:migrate
上記の例では'name'と'age'のカラムを持った'User'テーブルの自動生成が行われる。
適当にgenerateするだけですぐに動くものが作れる気軽さにびっくり。DBへのマイグレーションの非常に簡単だった。せこせこDDLとか作ったりする必要ないのかな?
Railsの開発環境
基本構成
基本構成は次の記事通り。
AtomでRailsを爆速開発する環境を作ってみた - Qiita
特に大きな問題は生じなかったが、「terminal-plus」が上手く動かない。 ウィンドウに何も表示されないし、何も入力できない。
terminal-plusが正常に動作しない時
atom 1.12.2 · Issue #386 · jeremyramin/terminal-plus · GitHub
apm
経由でインストールすれば良いとのことなので、「terminal-plus」をアンインストールした後に
apm install LarsKumbier/terminal-plus
を実行して、Atomを再起動すれば無事解消。
Atom stylesheet
スタイルシートでテーマのカスタマイズが出来るとのこと。肝心のスタイルシートがどこにあるかわからなかったのでメモ。
「メニュー > Atom > Stylesheet..」
これでstyles.less
が表示されるので好きなようにカスタマイズすればOK。
Ruby on Railsの勉強 -RailsTutorial 第1章-
タイトル通りの話、「Ruby on Railsの勉強」の備忘録として。
私はIT関連の仕事(俗に言うSIerというやつ)をしていますが、Javaをメインに比較的堅苦しい案件ばかりで他言語に触れる機会がなかった。自身の興味の範囲を広げる意味もふまえ、今更ながらRailsの勉強をしようと思う。
まずはチュートリアルから
第1章ゼロからデプロイまで
とりあえず何も考えず、チュートリアルの通りRailsのインストールを実施。
# railsのインストール gem install rails
適当にワークスペースを作成して、rails new hello_app
を実行。
rails new
を実行することによってアプリケーションとして必要なファイルセットが自動生成される模様。
次にGemfileをチュートリアル通りに修正する。Gemfileはアプリケーションで使用するライブラリの依存関係を管理するためのファイルらしい。
Gemfileを修正したらbundle install
を実行することでGemfileに記載した各種ライブラリのインストールが行われる。
ここまで準備が完了したらrails server
でアプリケーションが起動する。IPとポートの指定が可能だが取りあえずデフォルトのまま実行した。Safari等のブラウザでhttp://localhost:3000/
にアクセスすることでデフォルトのRailsページとやらが表示された。
その後、簡単なMVCの説明があり、コントローラの簡単な解説。
# application_controller.rb def hello render html: "hello, world!" end
上記は"hello, world!“っていうhtmlをレンダリングするってことかな? 次にルーティングの設定。ルーティングファイルに一筆追加した。
# config/routes.rb root 'application#hello'
これでルートパスへのアクセスを行うことでコントローラに定義したhello関数が呼び出されるのだろう。
その後の流れとして、1.4章ではGItの解説やBitbucketを利用したソースコードの管理、1.5章では仮想本番環境としてHerokuの利用についての解説が入る。
チュートリアルの第1章として"Hello World!“までは想定通りしていたが、GitにPaas(Heroku)と本番開発想定で解説されているおり、非常に良い教材と感じた。1章を写生しながら読み終えるのに1時間強かかったがこのまま継続していきたい。