http://github.com/making/thrift-facadeにコミットした。一応、jarを入れてあるからthriftインストールなしでも動く。
slf4jのバージョンが古いのはAndroid実機で動くバージョンまで下げたため。
$ mvn compile eclipse:m2eclipse
でEclipseにインポートする想定。
Thrift、通信データの拡張できるようにならないかなー。
struct InputBase {
1: string id;
}
struct HogeInput extends InputBase {
2: string name;
}
的な。そうすればサーバー側でinputに対応したサービスをDIできて、いい感じのマルチ言語アーキテクチャになる可能性があるのにな。
FaceBookさん対応して!
と、思ったけど、継承しちゃうと、基底クラスにプロパティ追加出来なくなるな。イマイチ。マーカーになるだけか。
Created at : 2010-02-04 03:26:51
Updated at : 2010-02-04 09:39:11
Category : Programming::Java::Thrift
前回leiningenをインストールしたので一番簡単なプロジェクトを作ってみる。
お決まりのHelloWorld
$ lein new helloworld
helloworldというディレクトリが作成され、プロジェクトのスケルトンができてます。中身はこんな感じ
$ find helloworld helloworld/ helloworld/.gitignore helloworld/project.clj helloworld/README helloworld/src helloworld/src/helloworld.clj helloworld/test
project.cljを開いて以下のように追記。
(defproject helloworld "1.0.0-SNAPSHOT" :description "FIXME: write" :dependencies [[org.clojure/clojure "1.1.0-alpha-SNAPSHOT"] [org.clojure/clojure-contrib "1.0-SNAPSHOT"]] ;; 以下追記。スタンドアロンjarのエントリポイント(Javaでいう所の static void main(String[] args)メソッドがあるフネームスペースを指定) :main helloworld )
次にsrc/helloworld.cljを以下のように編集。
(ns helloworld
(:gen-class)
)
;; javaでいうpublic static void main(String[] args)
(defn -main [& args]
(println "Hello World!!")
)
lein経由でreplを立ち上げると最初からleinとプロジェクトがクラスパスに入ってます。
$ cd helloworld $ lein repl user=> (use 'clojure.contrib.classpath) user=> (doseq [c (classpath)] (println (.getAbsolutePath c))) /Users/maki/work/clojure/helloworld/src /Users/maki/work/clojure/helloworld/classes /Users/maki/.m2/repository/leiningen/leiningen/1.0.1/leiningen-1.0.1-standalone.jar
さっきの-main関数を使ってみる。
user=> (use 'helloworld) user=> (-main) Hello World!!
ちなみにいま(import 'helloworld)をすると
user=> (import 'helloworld) java.lang.ClassNotFoundException: helloworld (NO_SOURCE_FILE:13)
と怒られます。クラスファイルがないからです。
コンパイルするとclojureのファイルをclassファイルにできます。
$ lein compile
[copy] Copying 2 files to /Users/maki/work/clojure/helloworld/lib
Compiling helloworld
$ find .
.
./.gitignore
./classes
./classes/helloworld$_main__14.class
./classes/helloworld$loading__6327__auto____12.class
./classes/helloworld.class
./classes/helloworld__init.class
./lib
./lib/clojure-1.1.0-alpha-20091215.130658-1.jar
./lib/clojure-contrib-1.0-20091212.214557-33.jar
./project.clj
(略)
helloworldのクラスファイルとなぜかclojureのjarまでもってきてくれました。これでREPLでimportできそう。
user=> (import 'helloworld) user=> (helloworld/-main) Hello World!!
ちなみにclasspathにもコピーされたjarが追加されてます
user=> (doseq [c (classpath)] (println (.getAbsolutePath c))) /Users/maki/work/clojure/helloworld/src /Users/maki/work/clojure/helloworld/classes /Users/maki/.m2/repository/leiningen/leiningen/1.0.1/leiningen-1.0.1-standalone.jar /Users/maki/work/clojure/helloworld/lib/clojure-1.1.0-alpha-20091215.130658-1.jar /Users/maki/work/clojure/helloworld/lib/clojure-contrib-1.0-20091212.214557-33.jar
REPLで試すのではなく、jarとしてスタンドアロンな実行可能プログラムをつくることもできます。
$ lein uberjar Including helloworld.jar Including clojure-1.1.0-alpha-20091215.130658-1.jar Including clojure-contrib-1.0-20091212.214557-33.jar $ find . . ./.gitignore ./classes ./classes/helloworld$_main__14.class ./classes/helloworld$loading__6327__auto____12.class ./classes/helloworld.class ./classes/helloworld__init.class ./helloworld-standalone.jar ./helloworld.jar ./lib ./lib/clojure-1.1.0-alpha-20091215.130658-1.jar ./lib/clojure-contrib-1.0-20091212.214557-33.jar (略)
helloworld-standalone.jarのエントリポイントがdefprojectで:mainに指定したファイルの-main関数になります(多分)
$ java -jar helloworld-standalone.jar Hello World!!
ちなみに、clojureで作った関数をライブラリ化したのがhelloworld.jarでこれを作るだけならlein jarでおk。
clojureのプロジェクト管理はleiningenで良さそう。
まだMavenの良さを全く活かしてないサンプルです。
一応Java屋さんってことになっているので今度はMavenを使ったサンプルを作るかも。
Created at : 2010-02-01 02:03:48
Updated at : 2010-02-01 03:02:27
Category : Programming::Lisp::Clojure::Leiningen
ToStringBuilder#reflectionToStringは便利だし、ログ出力に使うこともよくあるけど、HTTPリクエスト情報のパスワードとか生で出力しちゃうとセキュリティ的に問題。
とかいって毎回パスワードだけ手動で暗号化処理をして出力させるってのも面倒くさいし、保守性も悪い。
ということで暗号化したいフィールドはアノテーションをつけて暗号化するようにすれば楽そう。ToStringBuilderをいじる。
package am.ik.util.crypt.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Crypt {
// 暗号化処理クラスをここで指定できるようにしたら良さそう
}
package am.ik.util.crypt;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import am.ik.util.crypt.annotation.Crypt;
public class CryptReflectionToStringBuilder extends ReflectionToStringBuilder {
@SuppressWarnings("unchecked")
public CryptReflectionToStringBuilder(Object object, ToStringStyle style,
StringBuffer buffer, Class reflectUpToClass,
boolean outputTransients, boolean outputStatics) {
super(object, style, buffer, reflectUpToClass, outputTransients,
outputStatics);
}
@SuppressWarnings("unchecked")
@Override
protected void appendFieldsIn(Class clazz) {
// ReflectionToStringBuilder#appendFieldsInのコピペ...
if (clazz.isArray()) {
this.reflectionAppendArray(this.getObject());
return;
}
Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (Field field : fields) {
String fieldName = field.getName();
if (this.accept(field)) {
try {
Object fieldValue = this.getValue(field);
Crypt crypt = field.getAnnotation(Crypt.class);
if (crypt != null) {
// ここで適当な暗号化処理を行う
fieldValue = "****";
}
this.append(fieldName, fieldValue);
} catch (IllegalAccessException ex) {
throw new InternalError(
"Unexpected IllegalAccessException: "
+ ex.getMessage());
}
}
}
}
}
package am.ik.util.crypt;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
public class CryptToStringBuilder extends ToStringBuilder {
public CryptToStringBuilder(Object object, ToStringStyle style,
StringBuffer buffer) {
super(object, style, buffer);
}
public static String reflectionToString(Object object) {
return new CryptReflectionToStringBuilder(object, null, null, null,
false, false).toString();
}
}
public class CryptToStringBuilderTest {
public static class Hoge {
private final String name;
@Crypt
private final String password;
public Hoge(String name, String password) {
super();
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public String getPassword() {
return password;
}
}
@Test
public void test() {
Hoge hoge = new Hoge("foo", "bar");
System.out.println(CryptToStringBuilder.reflectionToString(hoge));
}
}
出力すると
am.ik.util.crypt.CryptToStringBuilderTest$Hoge@2c64f6cd[name=foo,password=****]
Created at : 2010-01-31 20:22:59
Updated at : 2010-01-31 20:25:15
Category : Programming::Java