JavaScript בג'אווה

ההודעה האחרונה ב- JavaLobby, עשרת התכונות הטובות ביותר ב- Java, הייתה פופולרית ביותר. בזמן כתיבת שורות אלה, זהו הדירוג המוביל ביותר בקטגוריית קישורים מובילים של DZone. בנוסף לכך פורסמה גם תשובה. ישנן תצפיות מעניינות רבות אודות תכונות שלא נוצלו בתוכנת Java בשני הפוסטים בבלוגים ואני מסכים עם כמה יותר מאחרים. עם זאת, פריט שבאמת משך את תשומת ליבי היה הקביעה שג'אווה SE 6 היא אחת מתכונות הג'אווה שאינן בשימוש.

אני מאוד נהנה לעבוד עם Java SE 6 וכתבתי על תכונות Java SE 6 או כתבתי עליהן בלוגים מספר פעמים בעבר. בפרסום זה בבלוג אני מתכוון להדגים חלק מהיכולת של Java SE 6 לארח קוד JavaScript.

רוב מפתחי Java ומפתחי JavaScript מבינים שמלבד ארבע האותיות "JAVA", ל- 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 + " "); } } 

הקוד המוצג לעיל מייצר פלט כמו זה שמוצג בתמונת המסך הבאה.

כפי שמדגים תמונה זו, מנוע ה- JavaScript של קרנף Mozilla נכלל ב- Java SE 6. של Sun. אנו רואים גם כמה "שמות נפוצים" הקשורים למנוע זה. ניתן להשתמש בכל אחד מהשמות הללו לחיפוש מנוע זה. בדוגמאות מאוחרות יותר בפוסט זה, אשתמש בשם הנפוץ "js" לחיפוש זה.

דוגמת הקוד הבאה תנצל את מנוע ה- Rhino JavaScript המסופק כדי לבצע קוד JavaScript מקוד Java. במקרה זה, ננצל את הפונקציה 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()); } } 

הקוד שלמעלה קורא ישירות ל- JavaScript בשיטת ScriptEngine.eval (String) כדי להעריך את המחרוזת שסופקה המכילה תחביר JavaScript. לפני קריאה evalלשיטה, שני פרמטרים "מועברים" (מאוגדים) לקוד JavaScript באמצעות קריאות ScriptEngine.put (String, Object). לגישה לאובייקט התוצאה של ה- JavaScript שבוצע בקוד Java באמצעות קריאת ScriptEngine.get (String).

כדי להדגים את הקוד הנ"ל באמצעות 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 משמש, הפלט נראה דומה לזה שמוצג בתמונת המסך הבאה.

דוגמה זו מספיקה כדי להדגים כמה קל להפעיל פונקציונליות של JavaScript מתוך Java SE 6. עם זאת, ניתן ליישם זאת באופן כללי ביתר שאת כפי שתיארו שתי הדוגמאות הבאות. הדוגמה הראשונה מציגה קריאה ל- 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 שניתן לעבד. זה כנראה לא הרעיון הטוב ביותר לקוד ייצור, אך מקל על הדגמת השימוש בתכונות JavaScript שונות בתוך Java.

הדוגמה הראשונה לשימוש בעיבוד JavaScript יחסית שרירותי זה מנצלת את אובייקט ה- Date של JavaScript. קוד הדוגמה מוצג בהמשך.

 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השיטה זורקת חריגה זה בדק אם יש שגיאה בביצוע / הערכת הסקריפט שסופק. שיטה זו גם זורקת NullPointerException אם המחרוזת שסופקה היא אפסית. הקוד המשמש לאילוץ שגיאת סקריפט מוצג בהמשך.

 /** * 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), אך זה בדיוק מה שדרוש כדי להדגים את ScriptException.toString (), הנקרא כחלק מטיפול בחריגים בשיטה המוצגת לעיל לטיפול במחרוזת JavaScript שרירותית . כאשר הקוד מבוצע, אנו רואים את מידע החריג כפי שמוצג בתמונה הבאה.

החלק של הפלט שמקורו ScriptException.toString()הוא החלק שאומר: "javax.script.ScriptException: sun.org.mozilla.javascript.internal.EvaluatorException: חסר; לפני הצהרה (# 1) בשורה מספר 1."

זה ScriptExceptionמכיל את שם הקובץ, מספר השורה ומספר העמודות של החריג, מה שמועיל במיוחד אם ניתן להעריך קובץ עם קוד JavaScript.

סיכום

Java SE 6 מקל על השימוש ב- JavaScript בתוך קוד Java. מנועי סקריפט אחרים יכולים להיות משויכים גם לג'אווה, אך זה שימושי שיש אחד שמסופק מחוץ לקופסה עם Mozilla Rhino.

תמונת מצב של קוד ומסך פלט מלא

לשם השלמות, אני כולל את רישום הקוד השלם במקום אחד כאן ואת הפלט שהתקבל לאחר מכן.

JavaScriptInJavaExample.java