JavaScript di Java

Posting JavaLobby baru-baru ini The Top 10 Unused Features in Java telah sangat populer. Pada saat penulisan ini, ini adalah posting peringkat teratas dalam kategori Tautan Teratas DZone. Sebagai tambahan, balasannya juga telah diposting. Ada banyak pengamatan menarik tentang fitur yang kurang dimanfaatkan di Java di kedua posting blog dan saya setuju dengan beberapa lebih dari yang lain. Namun, hal yang sangat menarik perhatian saya adalah pernyataan bahwa Java SE 6 adalah salah satu fitur Java yang paling tidak digunakan.

Saya sangat menikmati bekerja dengan Java SE 6 dan telah menulis atau membuat blog tentang fitur Java SE 6 beberapa kali sebelumnya. Dalam posting blog ini, saya bermaksud untuk menunjukkan sebagian dari kemampuan Java SE 6 untuk menjalankan kode JavaScript host.

Sebagian besar pengembang Java dan pengembang JavaScript memahami bahwa selain empat huruf "JAVA", JavaScript dan Java memiliki sangat sedikit kesamaan selain beberapa warisan mirip C. Namun, terkadang berguna untuk menjalankan bahasa skrip dari dalam kode Java dan Java SE 6 mengizinkannya.

Paket javax.script diperkenalkan dengan Java SE 6 dan mencakup kelas, antarmuka, dan pengecualian yang diperiksa terkait penggunaan mesin skrip dalam Java. Posting blog ini akan fokus pada ScriptEngineFactory, ScriptEngineManager, ScriptEngine, dan ScriptException.

Salah satu hal pertama yang mungkin ingin dilakukan adalah menentukan mesin skrip mana yang sudah tersedia. Potongan kode berikutnya menunjukkan betapa mudahnya ini dilakukan dengan 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 + " "); } } 

Kode yang ditunjukkan di atas menghasilkan keluaran seperti yang ditunjukkan pada cuplikan layar berikutnya.

Seperti yang ditunjukkan gambar ini, mesin JavaScript Mozilla Rhino disertakan dengan Java SE 6 milik Sun. Kita juga melihat beberapa "nama umum" yang terkait dengan mesin khusus ini. Salah satu nama ini dapat digunakan untuk mencari mesin ini. Dalam contoh selanjutnya di posting ini, saya akan menggunakan nama umum "js" untuk pencarian ini.

Contoh kode berikutnya akan memanfaatkan mesin JavaScript Rhino yang disediakan untuk menjalankan beberapa kode JavaScript dari kode Java. Dalam kasus ini, kita akan memanfaatkan fungsi toExponential JavaScript.

 /** * 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()); } } 

Kode di atas secara langsung memanggil JavaScript menggunakan metode ScriptEngine.eval (String) untuk mengevaluasi String yang disediakan berisi sintaks JavaScript. Sebelum evalmetode dipanggil, dua parameter "diteruskan" (terikat) ke kode JavaScript melalui panggilan ScriptEngine.put (String, Object). Objek hasil dari JavaScript yang dieksekusi diakses dalam kode Java menggunakan panggilan ScriptEngine.get (String).

Untuk mendemonstrasikan kode di atas menggunakan toExponentialfungsi tersebut, saya akan menggunakan kode "klien" berikut.

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); 

Jika kode di atas dijalankan terhadap metode writeNumberAsExponential yang ditunjukkan sebelumnya dan JavaScript digunakan, hasilnya akan tampak mirip dengan yang ditampilkan di snapshot layar berikutnya.

Contoh ini cukup untuk mendemonstrasikan betapa mudahnya memanggil fungsionalitas JavaScript dari dalam Java SE 6. Namun, ini dapat diimplementasikan secara lebih umum seperti yang akan ditunjukkan oleh dua contoh berikutnya. Contoh pertama menunjukkan pemanggilan JavaScript yang relatif arbitrer tanpa parameter yang lolos / terikat dan contoh kedua menunjukkan pemanggilan JavaScript yang relatif arbitrer dengan parameter yang diteruskan / terikat.

String JavaScript yang relatif sewenang-wenang dapat diproses dengan kode yang mirip dengan yang ditampilkan berikutnya.

 /** * 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; } 

Kode di atas memberikan sedikit fleksibilitas dalam hal JavaScript yang dapat diproses. Ini mungkin bukan ide terbaik untuk kode produksi, tetapi membuatnya lebih mudah untuk mendemonstrasikan penggunaan berbagai fitur JavaScript dalam Java.

Contoh pertama untuk menggunakan pemrosesan JavaScript yang relatif sewenang-wenang ini memanfaatkan objek Tanggal JavaScript. Kode sampel ditampilkan berikutnya.

 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) ); 

Kode ini menetapkan bahwa Tanggal JavaScript harus diambil (yang akan menjadi tanggal saat ini) dan bulan itu, tanggal bulan, dan tahun penuh harus diambil dari Tanggal yang dipakai itu. Output untuk ini muncul berikutnya.

Contoh terakhir bekerja pada String JavaScript arbitrer tetapi tidak menggunakan parameter apa pun. Contoh berikutnya menunjukkan penyediaan parameter untuk pemrosesan String JavaScript arbitrer ini karena menunjukkan penggunaan fungsi pow JavaScript. Kode untuk contoh ini dicantumkan berikutnya.

 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) ); 

Keluaran dari menjalankan contoh ini ditunjukkan pada cuplikan layar berikut.

Untuk contoh terakhir saya dari postingan blog ini, saya mendemonstrasikan toString()output standar yang ScriptExceptiondideklarasikan di beberapa contoh sebelumnya. The ScriptEngine.evalmetode melempar pengecualian ini diperiksa jika ada kesalahan dalam mengeksekusi / mengevaluasi script yang disediakan. Metode ini juga menampilkan NullPointerException jika String yang diberikan adalah null. Kode yang digunakan untuk memaksa kesalahan skrip ditampilkan berikutnya.

 /** * 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)); } 

Kode ini menyediakan skrip yang tidak masuk akal (dalam hal sintaks JavaScript), tetapi itulah yang diperlukan untuk mendemonstrasikan ScriptException.toString (), yang disebut sebagai bagian dari penanganan pengecualian dalam metode yang ditunjukkan di atas untuk menangani String JavaScript arbitrer . Ketika kode dijalankan, kita melihat informasi pengecualian seperti yang ditunjukkan pada gambar berikutnya.

Porsi keluaran yang berasal ScriptException.toString()adalah bagian yang menyatakan: "javax.script.ScriptException: sun.org.mozilla.javascript.internal.EvaluatorException: missing; before statement (# 1) in at line number 1."

The ScriptExceptionberisi nama file, nomor baris, dan jumlah kolom pengecualian, yang sangat membantu jika file dengan kode JavaScript disediakan untuk evaluasi.

Kesimpulan

Java SE 6 memudahkan penggunaan JavaScript dalam kode Java. Mesin skrip lain juga dapat dikaitkan dengan Java, tetapi akan berguna untuk menyediakan satu mesin skrip yang disediakan bersama Mozilla Rhino.

Kode Lengkap dan Snapshot Layar Output

Untuk kelengkapan, saya menyertakan daftar kode lengkap di satu tempat di sini dan keluaran yang dihasilkan setelah itu.

JavaScriptInJavaExample.java