スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

リフレクションによる動的メソッド呼び出し

フレームワークのコア部分には、リフレクション機能を仕様したメタプログラミングによるメソッドの動的呼び出しがよく行われている。
ユーザーからのリクエストに応じて、都度、コントローラのメソッド呼び出しを変えるということを実現するためである。
リフレクションの機能を利用するのが初めてだったので、プロトタイプ的に実装したので掲載しておく。

このプログラムでは、URLのようにスラッシュ区切りの文字列でリクエストが渡されることを前提とする。
スラッシュで区切られた1番目がコントローラクラスのクラス名、2番目がメソッド名。
3番目以降はメソッドに渡す引数の値。


Router.java
package app;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

public class Router {

public String[] readRequest(String req){
return req.split("/");
}

public void invokeControllerMethod(String[] elements) throws ClassNotFoundException, IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException{
Class clazz = Class.forName("controller." + elements[0]);
Object objCtrlr = clazz.getConstructor().newInstance();
Method[] methods = clazz.getMethods();
Method method = null;

// 引数で指定されたメソッド名からメソッドの実体を取得
for(Method methodTmp: methods){
if(methodTmp.getName().equals(elements[1])){
method = methodTmp;
System.out.println(method.getName());
Class types[] = method.getParameterTypes();
for(Class type : types){
System.out.println(type.getName());
}
}
}

//コール対象のメソッドのパラメータ群の型群を取得して配列に確保
Class[] types = method.getParameterTypes();
int length = types.length;
for(int i = 0; i < length; i++){
//プリミティブ型の場合、ラッパークラス型にして確保
if(types[i].getName() == "int"){
types[i] = Integer.class;
}
else if(types[i].getName() == "short"){
types[i] = Short.class;
}
// 以下、他のプリミティブ型の場合の処理
// else if(types[i].getName() == "byte"){
// ...
}

//各パラメータの型クラスの valueOf メソッド群を配列に確保
Method[] valueOfMethods = new Method[length];
for(int i = 0; i < length; i++) {
//String 型は valueOf(String s) が存在しないため、valueOf(Object o) メソッド
if(types[i].getName().equals("java.lang.String")) {
valueOfMethods[i] = types[i].getMethod("valueOf", Object.class);
}
//プリミティブ型はラッパークラスの valueOf(String s) メソッド
else if(types[i].getName() == "java.lang.Integer"){
valueOfMethods[i] = types[i].getMethod("valueOf", String.class);
}
// 以下、他のプリミティブ型の場合の処理
// if(types[i].getName() == "java.lang.Short"){
// ...
}

// 引数のみの配列とする
String[] params = Arrays.copyOfRange(elements, 2, elements.length);

// 引数の数に応じて、渡す引数を変えて対象メソッドをコール
// 引数は、コール直前に valueOfすることで、実質、適正な型にキャストする
// 呼び出し先の引数定義がプリミティブ型の場合、ラッパークラス型で渡してボクシングする
switch(length) {
case 0:
method.invoke(objCtrlr);
break;
case 1:
method.invoke(objCtrlr, valueOfMethods[0].invoke(params[0], params[0]));
break;
case 2:
method.invoke(objCtrlr, valueOfMethods[0].invoke(params[0], params[0]),
valueOfMethods[1].invoke(params[1], params[1]));
break;
case 3:
method.invoke(objCtrlr, valueOfMethods[0].invoke(params[0], params[0]),
valueOfMethods[1].invoke(params[1], params[1]),
valueOfMethods[2].invoke(params[2], params[2]));
break;
case 4:
method.invoke(objCtrlr, valueOfMethods[0].invoke(params[0], params[0]),
valueOfMethods[1].invoke(params[1], params[1]),
valueOfMethods[2].invoke(params[2], params[2]),
valueOfMethods[3].invoke(params[3], params[3]));
break;
// 以降、パラメータ数が増えたときの処理
}
}
}



EntryPoint.java
package app;

import java.lang.reflect.InvocationTargetException;
import controller.ConcreteController;

public class EntryPoint {

/**
* @param args
*/
public static void main(String[] args) throws IllegalArgumentException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
System.out.println("Program start");

// analyze request
Router router = new Router();
String[] elements = router.readRequest(args[0]);
router.invokeControllerMethod(elements);

System.out.println("Program end");
}

}

FC2 Management

Velocityテンプレートエンジンのサンプルプログラム

Javaのテンプレートエンジンとして有名なのはVelocityであろう。
以前、XMLのデータのレイアウト変換に使ったことがある。
今回、PBL活動の中でコード生成ジェネレータを作成することになったので、
その際にも使えるかもしれないと、他のメンバーにVelocityの機能を示すため、
サンプルのプログラムを作成した。
githubに上げているので、入手はこちらから。
以下、主要なファイルの内容を掲載。

TemplateEngineVelocitySample/src/app/Main.java
package app;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import entity.Member;

public class Main {

/**
* @param args
*/
public static void main(String[] args) {
System.out.println("Program start");

// データのセット
List members = new ArrayList();
for(int i = 0; i <= 5; i++){
Member member = new Member();
List favoriteLessons = new ArrayList();
switch(i) {
case 0:
member.setName("しょー");
member.setOccupation("プログラマー(会社曰くシステムエンジニア(笑))");
favoriteLessons.add("ソフトウェア開発プロセス特論");
break;
case 1:
member.setName("たい");
member.setOccupation("DBエンジニア(けど、DB以外もいろいろやってます)");
favoriteLessons.add("Javaプログラミング技法");
favoriteLessons.add("オブジェクト指向開発特論");
favoriteLessons.add("ソフトウェア開発特論Ⅰ");
break;
case 2:
member.setName("ただ");
member.setOccupation("プログラマ兼PMみたいな仕事");
favoriteLessons.add("アーキテクト系や開発系");
break;
case 3:
member.setName("あっけ");
member.setOccupation("Javaプログラマ");
favoriteLessons.add("情報ビジネス特別講義などの一見ITとは関わりがなさそうな授業");
break;
case 4:
member.setName("あっき");
member.setOccupation("開発者");
favoriteLessons.add("情報アーキテクチャ特論II");
break;
case 5:
member.setName("りゅー");
member.setOccupation("プログラマ(と言ってるけど、業務でコードはまず書くことはなし)。タイトルはプロジェクトマネージャ、実態はクラウドインフラエンジニア兼ビジネス企画開発");
favoriteLessons.add("ソフトウェア工学特論");
favoriteLessons.add("システムモデリング(創造)");
favoriteLessons.add("OSS特論");
break;
}
member.setFavoriteLessons(favoriteLessons);
members.add(member);
}
System.out.println("Memberクラスのオブジェクトに、各メンバーの氏名、職種、好きな授業(複数可)のデータをセットしました");

// Velocity を利用して、テンプレートファイル上にデータを展開し、ファイルに出力
VelocityWrapper velWrapper;
try {
velWrapper = new VelocityWrapper("./template/AkiguchiPBL.vm"); // Velocity のラッパークラスのオブジェクトを生成 ※ラッパーオブジェクトの詳細はロジック追う必要はないかと
velWrapper.put("members", members); // データをセットした members オブジェクトを、テンプレートファイル上の "members" と関連付ける
String result = velWrapper.merge(); // テンプレート上にデータを展開し、ひとつの文字列オブジェクトとする
System.out.println("Memberクラスのオブジェクトの情報を、./template/AkiguchiPBL.vmのテンプレートファイル上に展開しました");

PrintWriter pw = new PrintWriter("output.xml", "UTF-8");
pw.print(result); // 文字列オブジェクトをファイルに出力
System.out.println("展開した情報を、./output.xmlとして出力しました");
pw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

System.out.println("Program end");
}

}


TemplateEngineVelocitySample/src/entity/Member.java
package entity;

import java.util.List;

public class Member {

private String name;
private String occupation;
private List favoriteLessons;

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getOccupation() {
return occupation;
}
public void setOccupation(String occupation) {
this.occupation = occupation;
}
public List getFavoriteLessons() {
return favoriteLessons;
}
public void setFavoriteLessons(List favoriteLessons) {
this.favoriteLessons = favoriteLessons;
}

}



TemplateEngineVelocitySample/template/AkiguchiPBL.vm




#foreach ( $member in $members )

$member.name
$member.occupation

#* *# #foreach ( $favoriteLesson in $member.favoriteLessons )
$favoriteLesson
#* *# #end

#end





TemplateEngineVelocitySample/output.xml





しょー
プログラマー(会社曰くシステムエンジニア(笑))

ソフトウェア開発プロセス特論


たい
DBエンジニア(けど、DB以外もいろいろやってます)

Javaプログラミング技法
オブジェクト指向開発特論
ソフトウェア開発特論Ⅰ


ただ
プログラマ兼PMみたいな仕事

アーキテクト系や開発系


あっけ
Javaプログラマ

情報ビジネス特別講義などの一見ITとは関わりがなさそうな授業


あっき
開発者

情報アーキテクチャ特論II


りゅー
プログラマ(と言ってるけど、業務でコードはまず書くことはなし)。タイトルはプロジェクトマネージャ、実態はクラウドインフラエンジニア兼ビジネス企画開発

ソフトウェア工学特論
システムモデリング(創造)
OSS特論




上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。