Scala から Jython で書いたクラスのオブジェクトを操作してみました。といっても Jython で書いたクラスのオブジェクトを Java で作成し、Scala でそのクラスオブジェクトを操作しています。
ほぼ「 Using Jython Within Java Applications 」に書いてある通りのことをやってます。
最後の main() の箇所のみ Scala に置き換えて実行してます。
英語のドキュメント読むの大変なので適当に読み飛ばしてます。なにか間違って解釈してたらゴメンナサイ。
環境
- Ubuntu 14.04 (Trusty Tahr) Server
- Scala 2.9.2
- Jython 2.7.0
- Java 1.7.0_95
Scala インストール
$ sudo apt-get install scala
Jython インストール
「 Ubuntu に Jython 2.7 インストール 」の通り
JythonObjectFactory を作成
Jython で書かれた様々なクラスを Java から呼び出すためのオブジェクトファクトリーを作成します。
mypackage/common/JythonObjectFactory.java 作成
$ cat mypackage/common/JythonObjectFactory.java
package mypackage.common;
import org.python.core.Py;
import org.python.core.PyObject;
import org.python.core.PySystemState;
/**
* Jython Object Factory using PySystemState
*/
public class JythonObjectFactory {
private final Class interfaceType;
private final PyObject klass;
// Constructor obtains a reference to the importer, module, and the class name
public JythonObjectFactory(PySystemState state, Class interfaceType, String moduleName, String className) {
this.interfaceType = interfaceType;
PyObject importer = state.getBuiltins().__getitem__(Py.newString("__import__"));
PyObject module = importer.__call__(Py.newString(moduleName));
klass = module.__getattr__(className);
System.err.println("module=" + module + ",class=" + klass);
}
// This constructor passes through to the other constructor
public JythonObjectFactory(Class interfaceType, String moduleName, String className) {
this(new PySystemState(), interfaceType, moduleName, className);
}
// All of the followng methods return
// a coerced Jython object based upon the pieces of information
// that were passed into the factory. The differences are
// between them are the number of arguments that can be passed
// in as arguents to the object.
public Object createObject() {
return klass.__call__().__tojava__(interfaceType);
}
public Object createObject(Object arg1) {
return klass.__call__(Py.java2py(arg1)).__tojava__(interfaceType);
}
public Object createObject(Object arg1, Object arg2) {
return klass.__call__(Py.java2py(arg1), Py.java2py(arg2)).__tojava__(interfaceType);
}
public Object createObject(Object arg1, Object arg2, Object arg3) {
return klass.__call__(Py.java2py(arg1), Py.java2py(arg2),
Py.java2py(arg3)).__tojava__(interfaceType);
}
public Object createObject(Object args[], String keywords[]) {
PyObject convertedArgs[] = new PyObject[args.length];
for (int i = 0; i < args.length; i++) {
convertedArgs[i] = Py.java2py(args[i]);
}
return klass.__call__(convertedArgs, keywords).__tojava__(interfaceType);
}
public Object createObject(Object... args) {
return createObject(args, Py.NoKeywords);
}
}
コンパイル
$ javac -classpath /.../some/where/jython.jar mypackage/common/JythonObjectFactory.java
- classpath はインストールした Jython の jython.jar への絶対パスを指定します。
コンパイルにより作成された JythonObjectFactory.class は一度作成したら変更することはありません。
Jython スクリプトを作成
building_module.py 作成
$ cat building_module.py
from mypackage.interfaces import BuildingType
class BuildingClass(BuildingType):
def __init__(self):
self.name = None
self.address = None
self.id = -1
def getBuildingName(self):
return self.name
def setBuildingName(self, name):
self.name = name;
def getBuildingAddress(self):
return self.address
def setBuildingAddress(self, address):
self.address = address
def getBuildingId(self):
return self.id
def setBuildingId(self, id):
self.id = id
Scala ではこの building_module の BuildingClass オブジェクトを操作します。
from mypackage.interfaces import BuildingType で BuildingType をインポートし、 BuildingClass を BuildingType から派生しています。
Java ではメソッドに渡す引き数や戻り値の型が明示されている必要があるので BuildingType が必要なようです。
この BuildingType を宣言する mypackage/interfaces/BuildingType.java 作成
$ cat mypackage/interfaces/BuildingType.java
package mypackage.interfaces;
public interface BuildingType {
public String getBuildingName();
public String getBuildingAddress();
public int getBuildingId();
public void setBuildingName(String name);
public void setBuildingAddress(String address);
public void setBuildingId(int id);
}
- BuildingType の 各メソッド (getBuildingName() とか) は Jython の BuildingClass の各メソッドに対応しています。
コンパイル
$ javac mypackage/interfaces/BuildingType.java
Scala で BuildingClass オブジェクトを操作
作成したフィル構成は以下のようになってます。
$ tree -a
.
├── building_module.py
└── mypackage
├── common
│ ├── JythonObjectFactory.class
│ └── JythonObjectFactory.java
└── interfaces
├── BuildingType.class
└── BuildingType.java
3 directories, 5 files
Scala 実行
$ scala -classpath /.../some/where/jython.jar
インポート
scala> import mypackage.common.JythonObjectFactory
scala> import mypackage.interfaces.BuildingType
BuildingClass オブジェクト作成
scala> var factory = new JythonObjectFactory(classOf[BuildingType], "building_module", "BuildingClass")
scala> var building = factory.createObject().asInstanceOf[BuildingType]
BuildingClass オブジェクト操作
scala> building.setBuildingName("TestName")
scala> building.setBuildingAddress("TestAddress")
scala> building.setBuildingId(123)
scala> println(building.getBuildingId() + " " + building.getBuildingName() + " " + building.getBuildingAddress())
123 TestName TestAddress
0 件のコメント:
コメントを投稿