2016년 12월 4일 일요일

LuaJ 에서 java 메소드 호출

들어가기에 앞서
Lua 를 잘 모르시는 분은 따로 검색을 해보시기 바랍니다.

Java에서 Lua를 사용하기 위해서(왜 갑자기 시작했는지 모릅니다.) 검색을 시작 하였습니다.
그러다가 LuaJ를 발견하게 되었습니다. Lua는 C로 구현 되어있어서 아무래도 C와 연결하기가 굉장히 쉽게 되어 있는데 Java가 갑자기 하고 싶어 졌네요

LuaJ를 받아다가 library를 넣고 스크립트를 넣는것은 굉장히 단순합니다.
아래 주소에서 소스포함 library를 받으면 됩니다.
https://sourceforge.net/projects/luaj/
일반적으로 java se 버전을 사용하므로 라이브러리 폴더에 luaj-jse-3.0.1.jar 파일을 자신의 프로젝트에 복사해서 아래와 같은 예제를 사용하면 됩니다.

Run a script in a Java Application

A simple hello, world example in luaj is:
 import org.luaj.vm2.*;
 import org.luaj.vm2.lib.jse.*;

 Globals globals = JsePlatform.standardGlobals();
 LuaValue chunk = globals.load("print 'hello, world'");
 chunk.call();
 
Loading from a file is done via Globals.loadFile():
 LuaValue chunk = globals.loadfile("examples/lua/hello.lua");
Chunks can also be loaded from a Reader as text source
 chunk = globals.load(new StringReader("print 'hello, world'"), "main.lua");
or an InputStream to be loaded as text source "t", or binary lua file "b":
 chunk = globals.load(new FileInputSStream("examples/lua/hello.lua"), "main.lua", "bt"));
A simple example may be found in
 examples/jse/SampleJseMain.java
You must include the library lib/luaj-jse-3.0.1.jar in your class path.


아주 간단합니다. 하지만 Lua는 이럴려고 사용하는게 아니죠? 결국 자신이 필요한 함수를 만들어야 하는데요 즉 Lua script -> java 코드의 호출이 필요하게됩니다.
일주일 정도 LuaJ를 본 것 같습니다.
Readme.html에 있는 예제가 아무리해도 안되는겁니다.
그래서 중요한점을 빨간색으로 표시해보았습니다.

Libraries of Java Functions

When require() is called, it will first attempt to load the module as a Java class that implements LuaFunction. To succeed, the following requirements must be met:
  • The class must be on the class path with name, modname.
  • The class must have a public default constructor.
  • The class must inherit from LuaFunction.
If luaj can find a class that meets these critera, it will instantiate it, cast it to LuaFunction then call() the instance with two arguments: the modname used in the call to require(), and the environment for that function. The Java may use these values however it wishes. A typical case is to create named functions in the environment that can be called from lua.
A complete example of Java code for a simple toy library is in examples/jse/hyperbolic.java
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.*;

public class hyperbolic extends TwoArgFunction {

 public hyperbolic() {}

 public LuaValue call(LuaValue modname, LuaValue env) {
  LuaValue library = tableOf();
  library.set( "sinh", new sinh() );
  library.set( "cosh", new cosh() );
  env.set( "hyperbolic", library );
  return library;
 }

 static class sinh extends OneArgFunction {
  public LuaValue call(LuaValue x) {
   return LuaValue.valueOf(Math.sinh(x.checkdouble()));
  }
 }
 
 static class cosh extends OneArgFunction {
  public LuaValue call(LuaValue x) {
   return LuaValue.valueOf(Math.cosh(x.checkdouble()));
  }
 }
}
In this case the call to require invokes the library itself to initialize it. The library implementation puts entries into a table, and stores this table in the environment.
The lua script used to load and test it is in examples/lua/hyperbolicapp.lua
 require 'hyperbolic'

 print('hyperbolic', hyperbolic)
 print('hyperbolic.sinh', hyperbolic.sinh)
 print('hyperbolic.cosh', hyperbolic.cosh)

 print('sinh(0.5)', hyperbolic.sinh(0.5))
 print('cosh(0.5)', hyperbolic.cosh(0.5))
For this example to work the code in hyperbolic.java must be compiled and put on the class path.


중요한 사실은 eclipse를 이용하게되면 실행시 bin폴더에 출력 파일들이 생성되게 되고 클래스를 찾는 위치는 bin폴더 아래 위치에서 시작되게 됩니다.
따라서 위의 예제에서 hyperbolic 가 aaa패키지 아래에 있는 class라면 bin/aaa/hyperbolic.class파일이 생성이 될텐데요. lua에서 호출시 require 'aaa/hyperbolic' 이런식으로 호출 되어져야 합니다.

그리고 녹색으로 표현한 env.set( "hyperbolic", library ); 부분이 없다면 lua에서 hyperbolic 심볼을 사용할 수 없게 됩니다. 따라서 그때에는 아래와 같은 방식으로 호출 해야합니다.
abc=require 'aaa/hyperbolic'
print('sinh(0.5)', abc.sinh(0.5))

전체적으로 동작이 잘 안되는것 같다고 한다면 class파일을 여기저기 복사하면서 테스트 해보면 됩니다.




댓글 없음:

댓글 쓰기