sitelink1 https://infoscis.github.io/2017/03/23/Riding-the-Nashorn/ 
sitelink2  
sitelink3  
sitelink4  
sitelink5  
sitelink6  

※ Nashorn 관련 연관 링크 모음

 

 

Nashorn 엔진은 JSR-223(Scripting for the Java Platform)의 자바 스크립트 구현이며 javax.script API의 구현체 입니다.

따라서 Java에서 JavaScript 코드를 사용하기 위해서는 Nashorn javax.script.ScriptEngine을 생성 해야 합니다.

 

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); //  --- (1)

engine.eval("print('Hello World');");

(1) 여기에서 사용할 수있는 Nashorn 엔진 이름은 “nashorn”, “javascript”및 “js”입니다.

 

위에서 볼 수 있듯이 JavaScript 코드는 엔진 객체의 eval() 메서드에 문자열로 전달하여 직접 실행할 수 있습니다.

또는 파일을 가리키는 FileReader 객체를 전달하여 .js 파일을 구문 분석(및 실행)을 할 수 있습니다.

 

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");

engine.eval(new FileReader("test.js"));

 

2.1. Java에서 JavaScript 함수 호출

Java 프로그램 내부에서 단일 JavaScript 구문 또는 JavaScript 파일을 실행하거나 JavaScript 함수를 호출할 수도 있습니다.

또한 Java 객체를 JavaScript 함수의 arguments로 전달하고, JavaScript 함수에서 호출한 Java 메서드로 데이터를 반환할 수 있습니다.

 

example.js

 

var sayHello = function(name) {

  print('Hello, ' + name + '!');

  return 'hello from javascript';

};

위와 같이 작성된 example.js에 정의된 sayHello 함수를 호출하려면,

먼저 아래의 코드에서 보는 바와 같이 engine 객체를 NashornScriptEngine에서 구현된 Invocable Interface로 캐스팅해야합니다.

Invocable Interface는 invokeFunktion() 메서드를 제공하는데, 이 메서드는 입력값으로 받은 JavaScript 함수이름과 arguments를 이용해 Javascript를 실행할수 있습니다.

 

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");

engine.eval(new FileReader("example.js"));

 

// cast the script engine to an invocable instance

Invocable invocable = (Invocable) engine;

 

Object result = invocable.invokeFunction("sayHello", "John Doe");

System.out.println(result);

System.out.println(result.getClass());

 

// Hello, John Doe!

// hello from javascript

// class java.lang.String

위에 기술한 코드는 콘솔에 세 줄을 출력합니다.

JavaScript의 sayHello 함수의 print()는 System.out에 pipe되어 출력하고, Java 코드의 두개 System.out.println() 메소드에서 sayHello 함수의 리턴값과 리턴값의 Class이름을 출력합니다.

 

 

2.2. Javascript에서 Java method 호출

JavaScript 코드에서 Java 메소드를 호출하거나 실행하는 반대의 경우도 간단합니다.

Java의 두 종류의 메소드를 가정해 보겠습니다.

 

MyJavaClass.java

 

package my.package;

public class MyJavaClass {

    public static String sayHello(String name) {

        return String.format("Hello %s from Java!", name);

    }

    public int add(int a, int b) {

        return a + b;

    }

}

Java 클래스는 Java.type API 확장을 통해 JavaScript에서 참조할 수 있습니다.

이는 Java의 import 문과 유사합니다. 

Java 클래스를 참조한 후에 sayhello() 메서드와 같은 static method는 바로 호출하여 결과를 System.out에 출력할 수 있습니다. 

또한 add()와 같은 일반 메서드들은 class의 인스턴스를 생성하여 호출할 수 있습니다.

 

var MyJavaClass = Java.type('my.package.MyJavaClass');

 

// call the static method

var greetingResult = MyJavaClass.sayHello('John Doe');

print(greetingResult);

 

// create a new intance of MyJavaClass

var myClass = new MyJavaClass();

var calcResult = myClass.add(1, 2);

print(calcResult);

 

// Hello John Doe from Java!

// 3

 

 

2.2.1. Nashorn의 type 변환

아래의 간단한 예제를 통해 JavaScript에서 Java 메서드를 호출할 때 Nashorn이 Java와 JavaScript 간의 형식 변환을 처리하는 방법을 확인할 수 있습니다.

 

public static void printType(Object object) {

    System.out.println(object.getClass());

}

 

MyJavaClass.printType('Hello');

// class java.lang.String

 

MyJavaClass.printType(123);

// class java.lang.Integer

 

MyJavaClass.printType(12.34);

// class java.lang.Double

 

MyJavaClass.printType(true);

// class java.lang.Boolean

 

MyJavaClass.printType(new Number(123));

// class jdk.nashorn.internal.objects.NativeNumber

// class jdk.nashorn.api.scripting.ScriptObjectMirror

 

MyJavaClass.printType(new Date());

// class jdk.nashorn.internal.objects.NativeDate

// class jdk.nashorn.api.scripting.ScriptObjectMirror

 

MyJavaClass.printType(new RegExp());

// class jdk.nashorn.internal.objects.NativeRegExp

// class jdk.nashorn.api.scripting.ScriptObjectMirror

 

MyJavaClass.printType({foo: 'bar'});

// class jdk.nashorn.internal.scripts.J04

// class jdk.nashorn.api.scripting.ScriptObjectMirror

 

  • Primitive JavaScript type은 적절한 Java 래퍼 클래스로 변환됩니다.
  • Native JavaScript 객체는 ScriptObjectMirror 내부의 각각 어댑터 클래스로 표현됩니다.

 

jdk.nashorn.internal의 클래스는 추후 변경 될 수 있으므로 클라이언트 코드에서 해당 클래스에 대해 프로그램을 작성하면 안됩니다.

 

 

2.3. ScriptObjectMirror

ScriptObjectMirror는 jdk.nashorn.api의 일부이며 기본 Javascript 내부 클래스 대신 Java 클라이언트 코드에서 사용하기위한 것입니다. 

이 미러 객체는 JavaScript의 기본 객체의 표현입니다. 

또한 Java Map 인터페이스를 구현하였으며, 객체, 메서드 및 속성에 대한 액세스를 제공합니다.

 

위의 예제를 조금 바꿔 보겠습니다.

 

public static void printObjectMirror(ScriptObjectMirror mirror) {

    System.out.println(mirror.getClassName() + ": " + Arrays.toString(mirror.getOwnKeys(true)));

}

마지막 네개의 JavaScript 함수 호출 (number, date, regexp 및 object literal)을 사용하여이 메서드를 호출하면 다음과 같습니다.

 

MyJavaClass.printObjectMirror(new Number(123));

MyJavaClass.printObjectMirror(new Date());

MyJavaClass.printObjectMirror(new RegExp());

MyJavaClass.printObjectMirror({

    foo: 'bar',

    bar: 'foo'

});

결과는 다음과 같습니다.

 

Number: []

Date: []

RegExp: [lastIndex, source, global, ignoreCase, multiline]

Object: [foo, bar]

또한 Java에서 JavaScript 객체의 멤버 함수를 호출할 수 있습니다.

firstName, lastName 속성과 getFullName() 함수를 가진 JavaScript Person 타입을 가정해 보겠습니다.

 

function Person(firstName, lastName) {

  this.firstName = firstName;

  this.lastName = lastName;

  this.getFullName = function() {

    return this.firstName + ' ' + this.lastName;

  }

}

Javascript의 getFullName() 함수는 ScriptObjectMirror 클래스의 callMember() 메서드를 이용해 호출할수 있습니다.

 

public static void getFullName(ScriptObjectMirror person) {

    System.out.println("Full name is: " + person.callMember("getFullName"));

}

person 객체를 Java 메서드에 전달하면 콘솔에 원하는 결과가 표시됩니다.

 

var person = new Person('John', 'Doe');

MyJavaClass.getFullName(person);

 

// Full name is: John Doe

 

 

2.4. Script engine 옵션

nashorn.args system property을 사용하여 Nashorn 스크립트 엔진을 customize 할 수 있습니다. 

예를 들어 아래와 같이 스트립팅 모드 사용옵션을 -Dnashorn.args = ...을 이용하여 지정할 수 있습니다.

 

$ java -Dnashorn.args=-scripting MyJavaClass

customize 옵션을 파라메터로 넘겨 Nashorn engine을 생성할 수도 있습니다. 

이 경우 아래 예제와 같이 NashornScriptEngineFactory를 직접 인스턴스화 해야합니다.

 

NashornScriptEngineFactory factory = new NashornScriptEngineFactory();

ScriptEngine engine = factory.getScriptEngine(new String[] { "-scripting" });

jjs -help를 호출하여 사용 가능한 옵션을 확인할 수 있습니다.

 

 

2.5. Bindings / Context

ScriptContext는 하나 이상의 jsr223 “scope”이 Binding 되어 포함되어 있습니다. 

그리고 디폴트 scope으로 ENGINE_SCOPE와 GLOBAL_SCOPE의 두 가지가 있습니다.

 

  • ENGINE_SCOPE
  • GLOBAL_SCOPE

Nashorn 엔진이 생성되고 default context를 생성합니다.

 

ScriptContext defaultContext = engine.getContext();

default context의 ENGINE_SCOPE은 ECMAScript “global” object를 래핑한 인스턴스입니다. 

이 object는 최상위 script의 “this”입니다. 

따라서 이 scope 객체에서 “Object”, “Math”, “RegExp”, “undefined”와 같은 ECMAScript 최상위 객체를 액세스할 수 있습니다. 또한 GLOBAL_SCOPE은 같은 ScriptEngineManager로 작성된 모든 엔진 사이에 공유됩니다.

context에 변수들을 저장할 수 있지만 scope은 선택 사항이며 기본값은 ENGINE_SCOPE입니다.

 

ScriptContext context = engine.getContext();

// stores an object under the key `myKey` in the (engine scoped) context

context.setAttribute("myKey", object, ScriptContext.ENGINE_SCOPE);

// retrieves the object with key `myKey` from (engine scoped) context

context.getAttribute("myKey", ScriptContext.ENGINE_SCOPE);

 

Bindings b = context.getBindings(ScriptContext.ENGINE_SCOPE);

b.get("Object");    // gets ECMAScript "Object" constructor

b.get("undefined"); // ECMAScript 'undefined' value

Nashorn이 변수를 검색할 때 ENGINE_SCOPE에 없으면 GLOBAL_SCOPE Binding에서 검색합니다.

 

ECMAScript의 “global“ property가(최상위 레벨의 “this”) GLOBAL_SCOPE가 아닌 ENGINE_SCOPE에 있어 혼란이 있을 수 있습니다.

 

더 많은 Bindings와 ScriptContext정보는 wiki를 참고하세요.

 

 

[원문캡춰]

이미지 클릭시 캡춰본 다운로드함

 

thin.jpg

 

번호 제목 글쓴이 날짜 조회 수
331 ajax 로 post 데이터를 servlet 으로 전달 받기 (with nexacro) [1] secret 황제낙엽 2023.02.26 0
330 구글 클라우드 비전 API 사용하기 (Google Cloud Vision API) 황제낙엽 2023.02.22 8
329 람다식(Lambda Expressions in Java) file 황제낙엽 2022.12.03 2
328 ConcurrentLinkedQueue와 LinkedBlockingQueue 황제낙엽 2022.04.06 17
327 java.util.Queue file 황제낙엽 2022.04.06 5381
326 숫자형 클래스 BigInterger (int, long 범위 초과) 황제낙엽 2022.01.16 368
325 LocalDate.now() 오늘 날짜 황제낙엽 2022.01.16 7
324 HttpServletRequest, HttpServletResponse, JSONObject, POST 황제낙엽 2022.01.12 31
323 [java.lang.ProcessBuilder] “매개변수가 틀립니다” 혹은 ”Cannot run program” 황제낙엽 2021.10.15 191
322 특정 경로에서 쉘 명령어 실행하기 (ProcessBuilder) 황제낙엽 2021.10.08 54
321 HP-UX, IBM-AIX 황제낙엽 2021.06.23 55
320 nashorn ScriptEninge Test Project (war) file 황제낙엽 2021.05.19 157
319 람다(Lambda)와 함수형 인터페이스 황제낙엽 2021.05.10 19
318 javax.script.ScriptEngine 관련 참고사항 (sample java 포함) 황제낙엽 2021.05.09 463
317 Java Scripting API: GraalVM 적용해보기 황제낙엽 2021.05.09 23
316 Java Scripting API: 바인딩과 스크립트 컨텍스트 그리고 실행 성능 개선 file 황제낙엽 2021.05.09 15
315 Java Scripting API: 자바에서 자바스크립트의 함수를 호출할 수 있을까? file 황제낙엽 2021.05.09 345
» Java에서 Nashorn JavaScript 엔진 사용 file 황제낙엽 2021.05.09 230
313 [JSP] 파일 다운로드 테스트 file 황제낙엽 2021.04.12 123
312 ResultSet 을 순회하기 전에 사이즈 구하기 황제낙엽 2021.01.14 28