Programování

JavaScript v Javě

Nedávný příspěvek JavaLobby Top 10 nepoužívaných funkcí v Javě byl velmi populární. V době psaní tohoto článku se jedná o nejlépe hodnocený příspěvek v kategorii DZone Top Links. Kromě toho byla zveřejněna také odpověď na tuto otázku. V obou příspěvcích blogů je mnoho zajímavých postřehů o nevyužitých funkcích v Javě a s některými souhlasím více než s ostatními. Položkou, která mě opravdu upoutala, však bylo tvrzení, že Java SE 6 je jednou z nejvíce nepoužívaných funkcí Java.

Opravdu mě baví pracovat s Java SE 6 a v minulosti jsem o funkcích Java SE 6 psal nebo o nich blogoval. V tomto příspěvku na blogu mám v úmyslu předvést část schopnosti Java SE 6 hostovat spouštění kódu JavaScript.

Většina vývojářů Java a vývojářů JavaScriptu chápe, že kromě čtyř písmen „J-A-V-A“ mají JavaScript a Java kromě společného dědictví typu C společného i velmi málo společného. Přesto může být občas užitečné spustit skriptovací jazyk z kódu Java a Java SE 6 to umožňuje.

Balíček javax.script byl představen v prostředí Java SE 6 a obsahuje třídy, rozhraní a kontrolovanou výjimku týkající se používání skriptovacích strojů v prostředí Java. Tento příspěvek do blogu se zaměří na ScriptEngineFactory, ScriptEngineManager, ScriptEngine a ScriptException.

Jednou z prvních věcí, kterou byste mohli chtít udělat, je zjistit, které skriptovací motory jsou již k dispozici. Další fragment kódu ukazuje, jak snadné je to s Java SE 6.

finální správce ScriptEngineManager = nový 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 ("\ tBěžná jména / aliasy:"); for (final String engineAlias: scriptEngine.getNames ()) {System.out.println (engineAlias ​​+ ""); }} 

Kód zobrazený výše generuje výstup podobný tomu, který je zobrazen na následujícím snímku obrazovky.

Jak ukazuje tento obrázek, je JavaScriptový modul Mozilla Rhino součástí Java SE 6. Sun. Vidíme také některé „běžné názvy“, které jsou spojeny s tímto konkrétním motorem. K vyhledání tohoto enginu lze použít kterékoli z těchto jmen. V dalších příkladech v tomto příspěvku budu pro toto vyhledávání používat běžný název „js“.

Následující ukázka kódu využije poskytnutý JavaScriptový stroj Rhino k provedení nějakého kódu JavaScript z kódu Java. V tomto případě využijeme výhodu funkce toExponential JavaScriptu.

 / ** * Napište číslo v exponenciální formě. * * @param numberToWriteInExponentialForm Číslo, které má být reprezentováno v * exponenciální formě. * @param numberDecimalPlaces Počet desetinných míst, která mají být použita v * exponenciálním vyjádření. * / public static void writeNumberAsExponential (konečné číslo numberToWriteInExponentialForm, konečné 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 ("Číslo:" + exponenciální číslo); } catch (ScriptException scriptException) {LOGGER.severe ("ScriptException došlo k pokusu o zápis exponenciální:" + scriptException.toString ()); }} 

Výše uvedený kód přímo vyvolá JavaScript pomocí metody ScriptEngine.eval (String) k vyhodnocení poskytnutého řetězce obsahujícího syntaxi JavaScriptu. Před vyvoláním eval metoda, dva parametry jsou „předány“ (vázány) do kódu JavaScript pomocí volání ScriptEngine.put (String, Object). K objektu výsledku spuštěného JavaScriptu se přistupuje v kódu Java pomocí volání ScriptEngine.get (String).

K předvedení výše uvedeného kódu pomocí na exponenciální funkce, použiji následující „klientský“ kód.

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

Když je výše uvedený kód spuštěn proti metodě writeNumberAsExponential zobrazené dříve a je použit JavaScript, zobrazí se výstup podobný tomu, který je uveden na dalším snímku obrazovky.

Tento příklad stačí k prokázání toho, jak snadné je vyvolat funkčnost JavaScriptu z prostředí Java SE 6. To by však mohlo být implementováno ještě obecněji, jak ukážou další dva příklady. První příklad ukazuje vyvolání relativně libovolného JavaScriptu bez předaných / vázaných parametrů a druhý příklad ukazuje vyvolání relativně libovolného JavaScriptu s předanými / vázanými parametry.

Relativně libovolný řetězec JavaScriptu lze zpracovat pomocí kódu podobného tomu, který je zobrazen dále.

 / ** * Zpracuje předaný skript JavaScriptu, který by měl obsahovat přiřazení * k proměnné s názvem předepsaným zadaným nameOfOutput a * může obsahovat parametry předepsané inputParameters. * * @param javaScriptCodeToProcess Řetězec obsahující kód JavaScript, který má být * vyhodnocen. U tohoto řetězce není zkontrolován žádný typ platnosti a * může případně vést k vyvolání výjimky ScriptException, která by * byla zaznamenána. * @param nameOfOutput Název výstupní proměnné přidružené ke skriptu JavaScriptu poskytnutému *. * @param inputParameters Volitelná mapa názvů parametrů k hodnotám parametrů *, které mohou být použity v poskytnutém skriptu JavaScript. Tato mapa * může mít hodnotu null, pokud se ve skriptu neočekávají žádné vstupní parametry. * / 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 došlo k pokusu o zápis libovolného JavaScriptu '" + javaScriptCodeToProcess + "':" + scriptException.toString ()); } vrátit výsledek; } 

Výše uvedený kód poskytuje značnou flexibilitu, pokud jde o JavaScript, který lze zpracovat. To pravděpodobně není nejlepší nápad pro produkční kód, ale usnadňuje to demonstraci použití různých funkcí JavaScriptu v Javě.

První příklad použití tohoto relativně libovolného zpracování JavaScriptu využívá výhodu objektu Date JavaScript. Ukázkový kód je zobrazen dále.

 System.out.println ("Dnešní datum:" + 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)); 

Tento kód určuje, že by se mělo načíst datum JavaScriptu (což bude aktuální datum) a ten měsíc, datum měsíce a celý rok by se měl extrahovat z tohoto vytvořeného data. Výstup pro toto se objeví další.

Poslední příklad fungoval na libovolném řetězci JavaScriptu, ale nepoužíval žádné parametry. Následující příklad ukazuje poskytnutí parametrů k tomuto libovolnému zpracování řetězce JavaScriptu, protože ukazuje použití funkce pow Java. Kód tohoto příkladu je uveden dále.

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

Výstup ze spuštění tohoto příkladu je zobrazen na následujícím snímku obrazovky.

U mého posledního příkladu tohoto příspěvku na blogu ukazuji standard toString () výstup ScriptException deklarováno v některých předchozích příkladech. The ScriptEngine.eval metoda vyvolá tuto kontrolovanou výjimku, pokud dojde k chybě při provádění / vyhodnocování poskytnutého skriptu. Tato metoda také vyvolá NullPointerException, pokud je zadaný String null. Kód použitý k vynucení chyby skriptu je zobrazen dále.

 / ** * Úmyslně způsobí, že chyba zpracování skriptu zobrazí typ informací *, které ScriptException obsahuje. * / public static void testScriptExceptionHandling () {System.out.println (processArbitraryJavaScript ("Garbage In", "none", null)); } 

Tento kód poskytuje nesmyslný skript (z hlediska syntaxe JavaScriptu), ale to je přesně to, co je potřeba k předvedení ScriptException.toString (), který se nazývá jako součást zpracování výjimek ve výše uvedené metodě pro zpracování libovolného řetězce JavaScriptu . Když je kód spuštěn, vidíme informace o výjimce, jak je znázorněno na dalším obrázku.

Část výstupu, ze které pochází ScriptException.toString () je část, která uvádí: „javax.script.ScriptException: sun.org.mozilla.javascript.internal.EvaluatorException: missing; before statement (# 1) in at line number 1.“

The ScriptException obsahuje název souboru, číslo řádku a číslo sloupce výjimky, což je zvláště užitečné, pokud je k vyhodnocení poskytnut soubor s kódem JavaScript.

Závěr

Java SE 6 usnadňuje používání JavaScriptu v kódu Java. S Javou lze také spojit další skriptovací jádra, ale je užitečné mít jeden dodávaný s Mozilla Rhino přímo v krabici.

Kompletní snímek obrazovky a snímek obrazovky výstupu

Pro úplnost sem zahrnuji kompletní výpis kódu na jednom místě a výsledný výstup poté.

JavaScriptInJavaExample.java