JSON-RPCで転送するJavaオブジェクトをさくっと作成するユーティリティ の続き
昨日作成したJSON-RPCで転送するJavaオブジェクトをさくっと作成するユーティリティですが、Ruby→JSONへのシリアライズだけじゃなく、JSON→Rubyへのデシリアライズもサポートしてればさらに便利じゃね?と思い立って実装してみた。API呼び出しの結果として返されたハッシュが定義済みのJavaクラスであればそのインスタンスに変換して返します。
require 'rubygems' require 'uri' require 'httpclient' require 'json/lexer' require 'json/objects' module JsonRpc # クライアント class Client def initialize( name, host="http://localhost:8080", proxy=ENV["http_proxy"] ) @client = HTTPClient.new( proxy, "JsonClientLib") @client.set_cookie_store("cookie.dat") @name = name @host = host @id = 0 end def method_missing( name, *args ) body = "{ 'id':#{@id+=1},method:#{(@name+"."+name.to_s).to_json},params:#{args.to_json}}" result = @client.post(@host, body ) json = JSON::Lexer.new(result.content).nextvalue if json["error"] raise json["error"]["msg"] else JsonRpc.to_java_class(json["result"]) end end end #JSON-RPCで送付するJavaクラスを定義する。 #java_class:: 対応するJavaクラスのFQCN #attrs:: Javaクラスの属性一覧 #return:: Javaクラス def self.define( java_class, *attrs ) cl = Class.new(JsonRpc::JavaClass) {|klass| @java_class = java_class @attrs = attrs def self.java_class ; @java_class; end def self.attrs; @attrs; end def initialize( *args ) attrs = self.class.attrs args.each_index {|i| break if i >= attrs.length instance_variable_set("@" + attrs[i].to_s, args[i]) } end attrs.each {|a| attr a, true} } @@registory[java_class] = cl return cl end # 定義したJavaClass @@registory = {} # ハッシュをJavaClassにデシリアライズする。 def self.to_java_class( obj ) if obj.kind_of?( Hash ) hash = obj.inject({}){|r,i| r[i[0]] = to_java_class(i[1]); r } if ( obj["javaClass"] && @@registory.key?(obj["javaClass"]) ) java_class = @@registory[obj["javaClass"]] args = java_class.attrs.map {|a| hash[to_jar_attr_name( a )] } return java_class.new(*args) else return hash end elsif obj.kind_of?( Array ) return obj.map {|i| to_java_class( i ) } else return obj end end def self.to_jar_attr_name( name ) tmp = name.to_s.split(/_/) return ([tmp[0]] + tmp[1..-1].map{|i| i.capitalize}).join end # Javaクラスの基底クラス class JavaClass def to_hash h = {"javaClass"=>self.class.java_class} attrs = self.class.attrs attrs.each {|attr| java_attr_name = JsonRpc.to_jar_attr_name( attr ) h[java_attr_name] = instance_variable_get("@" + attr.to_s) } return h end def to_json to_hash.to_json end end end
利用例は以下。
# Kittenオブジェクトを定義 Kitten = JsonRpc::define( "test.Kitten", :id, :name, :age ) # クライアント作成 client = JsonRpc::Client.new( "dao", "http://localhost:8888/json" ) # API呼び出し。 p client.put( Kitten.new( nil, "mii", 1 ))
実行結果です。
#<Kitten:0x7fd308f4 @name="mii", @age=1, @id={"kind"=>"Kitten", "javaClass"=>"com.google.appengine.api.datastore.Key", "id"=>4}>