자바 자바 스크립트

최근 JavaLobby 게시물 The Top 10 Unused Features in Java는 매우 인기가 있습니다. 이 글을 쓰는 시점에서 DZone Top Links 카테고리에서 가장 높은 순위의 게시물입니다. 또한 그것에 대한 답글도 게시되었습니다. 두 블로그 게시물 모두에서 Java의 활용도가 낮은 기능에 대한 흥미로운 관찰이 많이 있으며 나는 다른 것보다 더 많은 것에 동의합니다. 하지만 정말 관심을 끌었던 항목은 Java SE 6이 가장 많이 사용되지 않는 Java 기능 중 하나라는 주장이었습니다.

저는 Java SE 6으로 작업하는 것을 정말 좋아하고 과거에 Java SE 6 기능에 대해 여러 번 작성하거나 블로그에 올렸습니다. 이 블로그 게시물에서 Java SE 6의 JavaScript 코드 실행을 호스팅하는 기능의 일부를 보여 드리고자합니다.

대부분의 자바 개발자와 자바 스크립트 개발자는 "JAVA"라는 네 글자 외에 자바 스크립트와 자바는 C와 유사한 유산 외에 공통점이 거의 없다는 것을 이해합니다. 그래도 Java 코드 내에서 스크립팅 언어를 실행하는 것이 유용 할 수 있으며 Java SE 6에서는이를 허용합니다.

javax.script 패키지는 Java SE 6과 함께 도입되었으며 Java 내에서 스크립팅 엔진 사용과 관련된 클래스, 인터페이스 및 확인 된 예외를 포함합니다. 이 블로그 게시물은 ScriptEngineFactory, ScriptEngineManager, ScriptEngine 및 ScriptException에 중점을 둘 것입니다.

가장 먼저 할 수있는 작업 중 하나는 이미 사용 가능한 스크립팅 엔진을 확인하는 것입니다. 다음 코드 스 니펫은 Java SE 6에서 이것이 얼마나 쉬운 지 보여줍니다.

final ScriptEngineManager manager = new ScriptEngineManager(); for (final ScriptEngineFactory scriptEngine : manager.getEngineFactories()) { System.out.println( scriptEngine.getEngineName() + " (" + scriptEngine.getEngineVersion() + ")" ); System.out.println( "\tLanguage: " + scriptEngine.getLanguageName() + "(" + scriptEngine.getLanguageVersion() + ")" ); System.out.println("\tCommon Names/Aliases: "); for (final String engineAlias : scriptEngine.getNames()) { System.out.println(engineAlias + " "); } } 

위에 표시된 코드는 다음 화면 스냅 샷에 표시된 것과 같은 출력을 생성합니다.

이 이미지에서 알 수 있듯이 Mozilla Rhino JavaScript 엔진은 Sun의 Java SE 6에 포함되어 있습니다. 또한이 특정 엔진과 관련된 "일반적인 이름"도 볼 수 있습니다. 이러한 이름은이 엔진을 조회하는 데 사용할 수 있습니다. 이 게시물의 이후 예제에서는이 조회에 공통 이름 "js"를 사용합니다.

다음 코드 샘플은 제공된 Rhino JavaScript 엔진을 활용하여 Java 코드에서 일부 JavaScript 코드를 실행합니다. 이 경우 JavaScript의 toExponential 함수를 활용합니다.

 /** * Write number in exponential form. * * @param numberToWriteInExponentialForm The number to be represented in * exponential form. * @param numberDecimalPlaces The number of decimal places to be used in the * exponential representation. */ public static void writeNumberAsExponential( final Number numberToWriteInExponentialForm, final int numberDecimalPlaces) { final ScriptEngine engine = manager.getEngineByName("js"); try { engine.put("inputNumber", numberToWriteInExponentialForm); engine.put("decimalPlaces", numberDecimalPlaces); engine.eval("var outputNumber = inputNumber.toExponential(decimalPlaces);"); final String exponentialNumber = (String) engine.get("outputNumber"); System.out.println("Number: " + exponentialNumber); } catch (ScriptException scriptException) { LOGGER.severe( "ScriptException encountered trying to write exponential: " + scriptException.toString()); } } 

위의 코드는 ScriptEngine.eval (String) 메서드를 사용하여 JavaScript를 직접 호출하여 JavaScript 구문이 포함 된 제공된 문자열을 평가합니다. eval메서드를 호출하기 전에 ScriptEngine.put (String, Object) 호출을 통해 두 개의 매개 변수가 JavaScript 코드에 "전달"(바인딩)됩니다. 실행 된 JavaScript의 결과 객체는 ScriptEngine.get (String) 호출을 사용하여 Java 코드에서 액세스됩니다.

toExponential함수를 사용하여 위 코드를 설명 하기 위해 다음 "클라이언트"코드를 사용합니다.

final int sourceNumber = 675456; writeNumberAsExponential(sourceNumber, 1, System.out); writeNumberAsExponential(sourceNumber, 2, System.out); writeNumberAsExponential(sourceNumber, 3, System.out); writeNumberAsExponential(sourceNumber, 4, System.out); writeNumberAsExponential(sourceNumber, 5, System.out); 

위의 코드가 앞에서 설명한 writeNumberAsExponential 메서드에 대해 실행되고 JavaScript가 사용되면 출력은 다음 화면 스냅 샷에 표시된 것과 유사하게 나타납니다.

이 예제는 Java SE 6 내에서 JavaScript 기능을 호출하는 것이 얼마나 쉬운 지 보여주기에 충분합니다. 그러나 다음 두 예제에서 설명하는 것처럼 훨씬 더 일반적으로 구현할 수 있습니다. 첫 번째 예제는 전달 / 바운딩 된 매개 변수가없는 비교적 임의의 JavaScript 호출을 보여주고 두 번째 예제는 전달 / 바운딩 된 매개 변수를 사용하여 상대적으로 임의의 JavaScript 호출을 보여줍니다.

비교적 임의의 JavaScript 문자열은 다음에 표시된 것과 유사한 코드로 처리 할 수 ​​있습니다.

 /** * Process the passed-in JavaScript script that should include an assignment * to a variable with the name prescribed by the provided nameOfOutput and * may include parameters prescribed by inputParameters. * * @param javaScriptCodeToProcess The String containing JavaScript code to * be evaluated. This String is not checked for any type of validity and * might possibly lead to the throwing of a ScriptException, which would * be logged. * @param nameOfOutput The name of the output variable associated with the * provided JavaScript script. * @param inputParameters Optional map of parameter names to parameter values * that might be employed in the provided JavaScript script. This map * may be null if no input parameters are expected in the script. */ public static Object processArbitraryJavaScript( final String javaScriptCodeToProcess, final String nameOfOutput, final Map inputParameters) { Object result = null; final ScriptEngine engine = manager.getEngineByName("js"); try { if (inputParameters != null) { for (final Map.Entry parameter : inputParameters.entrySet()) { engine.put(parameter.getKey(), parameter.getValue()); } } engine.eval(javaScriptCodeToProcess); result = engine.get(nameOfOutput); } catch (ScriptException scriptException) { LOGGER.severe( "ScriptException encountered trying to write arbitrary JavaScript '" + javaScriptCodeToProcess + "': " + scriptException.toString()); } return result; } 

위의 코드는 처리 할 수있는 JavaScript 측면에서 상당한 유연성을 제공합니다. 이것은 아마도 프로덕션 코드에 대한 최선의 아이디어는 아니지만 Java 내에서 다양한 JavaScript 기능의 사용을 더 쉽게 보여줄 수 있습니다.

비교적 임의의 JavaScript 처리를 사용하는 첫 번째 예제는 JavaScript의 Date 객체를 활용합니다. 다음은 샘플 코드입니다.

 System.out.println( "Today's Date: " + processArbitraryJavaScript( "var date = new Date(); var month = (date.getMonth()+1).toFixed(0)", "month", null) + "/" + processArbitraryJavaScript( "var date = new Date(); var day = date.getDate().toFixed(0)", "day", null) + "/" + processArbitraryJavaScript( "var date = new Date(); var year = date.getFullYear().toFixed(0)", "year", null) ); 

이 코드는 JavaScript 날짜를 검색하고 (현재 날짜가 됨) 인스턴스화 된 해당 날짜에서 해당 월, 날짜 및 전체 연도를 추출해야 함을 지정합니다. 이에 대한 출력이 다음에 나타납니다.

마지막 예제는 임의의 JavaScript 문자열에서 작동했지만 매개 변수를 사용하지 않았습니다. 다음 예제는 JavaScript의 pow 함수 사용을 보여주기 때문에이 임의의 JavaScript 문자열 처리에 매개 변수를 제공하는 방법을 보여줍니다. 이 예제의 코드는 다음과 같습니다.

 final Map exponentParameters = new HashMap(); exponentParameters.put("base", 2); exponentParameters.put("exponent", 5); System.out.println( "2 to the 5 is: " + processArbitraryJavaScript( "var answer = Math.pow(base,exponent)", "answer", exponentParameters) ); 

이 예제를 실행 한 결과는 다음 화면 스냅 샷에 표시됩니다.

이 블로그 게시물의 마지막 예제 를 위해 이전 예제에서 선언 된 의 표준 toString()출력을 보여줍니다 ScriptException. ScriptEngine.eval제공된 스크립트를 평가 / 실행에 오류가있는 경우에있어서이 체크 예외를 던진다. 이 메서드는 제공된 String이 null 인 경우 NullPointerException도 throw합니다. 스크립트 오류를 ​​강제하는 데 사용되는 코드는 다음과 같습니다.

 /** * Intentionally cause script handling error to show the type of information * that a ScriptException includes. */ public static void testScriptExceptionHandling() { System.out.println(processArbitraryJavaScript("Garbage In", "none", null)); } 

이 코드는 (JavaScript 구문 측면에서) 무의미한 스크립트를 제공하지만, 임의의 JavaScript 문자열을 처리하기 위해 위에 표시된 메서드에서 예외 처리의 일부로 호출되는 ScriptException.toString ()을 보여주기 위해 정확히 필요한 것입니다. . 코드가 실행되면 다음 이미지와 같이 예외 정보가 표시됩니다.

출력에서 나오는 ScriptException.toString()부분은 "javax.script.ScriptException : sun.org.mozilla.javascript.internal.EvaluatorException : missing; before statement (# 1) in at line number 1"이라는 부분입니다.

ScriptException파일 이름, 줄 번호, 자바 스크립트 코드 파일이 평가를 위해 제공되는 경우에 특히 유용 예외의 열 번호가 포함되어 있습니다.

결론

Java SE 6을 사용하면 Java 코드 내에서 JavaScript를 간단하게 사용할 수 있습니다. 다른 스크립팅 엔진도 Java와 연결될 수 있지만 Mozilla Rhino와 함께 기본 제공되는 엔진을 사용하는 것이 편리합니다.

완전한 코드 및 출력 화면 스냅 샷

완전성을 위해 여기 한 곳에 전체 코드 목록을 포함하고 그 이후의 결과 출력을 포함합니다.

JavaScriptInJavaExample.java