Obsah
1. Získání základních informací o syntaxi vybraného skriptovacího jazyka
2. První demonstrační příklad – základní informace o syntaxi JavaScriptu
3. Chování javovských objektů v JavaScriptu či dalších skriptovacích jazycích
4. Druhý demonstrační příklad – výpis všech vlastností javovského objektu
5. Třetí demonstrační příklad – základní způsob volání getterů a setterů
6. Čtvrtý demonstrační příklad – zjednodušený způsob volání getterů a setterů
7. Pátý demonstrační příklad – JavaScript a přetížené metody v javovském objektu
8. Komentář k výsledkům předchozího demonstračního příkladu
1. Získání základních informací o syntaxi vybraného skriptovacího jazyka
V předchozí části seriálu o technologiích používaných ve virtuálním stroji programovacího jazyka Java (JVM – Java Virtual Machine) jsme se seznámili se základními rysy aplikačního programového rozhraní navrženého v rámci JSR 223. Toto aplikační rozhraní je určeno pro zjednodušení a současně i unifikaci při oboustranné komunikaci mezi aplikací naprogramovanou přímo v Javě a skriptem (většinou spouštěným přímo z této aplikace, i když je možné skript spouštět i z „shellu“), který může být vytvořen v jakémkoli programovacím jazyce, pro nějž je dostupný skriptovací engine – důležité je to, že aplikační programové rozhraní, které vývojář vytvářející program v Javě používá, zůstává stejné bez ohledu na to, jaký skriptovací jazyk je ve skutečnosti využíván. Společně s proprietární Oracle JDK a taktéž OpenJDK je jeden ze skriptovacích enginů dodáván jako standardní součást distribuce JDK i JRE. Jeho jméno je Rhino a programovacím jazykem, který je tímto skriptovacím enginem implementován, je populární, ale i zatracovaný a mnohými programátory nepochopený JavaScript.
Minule jsme si ukázali, že před zavoláním skriptu je nejdříve nutné získat vhodný skriptovací engine. Pro jeho získání se nejdříve vytváří instance třídy ScriptEngineManager a poté je s využitím metod definovaných v této třídě, především metod getEngineByName(), getEngineByExtension() či getEngineByMimeType() získán objekt, který představuje skriptovací engine (tento objekt je instancí třídy implementující rozhraní ScriptEngine). Podrobnější informace o skriptovacím enginu je možné zjistit s využitím další třídy implementující rozhraní ScriptEngineFactory, která je na skriptovací engine navázána. Některé metody předepsané tímto rozhraním jsme si již ukázali minule, ovšem zbývá nám popis tří metod, jež je možné využít pro zjištění základních informací o syntaxi vybraného skriptovacího jazyka. Jedná se o metody getOutputStatement(), getMethodCallSyntax() a getProgram(), které budou součástí demonstračního příkladu uvedeného ve druhé kapitole.
2. První demonstrační příklad – základní informace o syntaxi JavaScriptu
Metoda ScriptEngineFactory.getOutputStatement() slouží ke zjištění toho, jakým způsobem se ve skriptu může vytisknout hodnota nějaké konstanty či proměnné. Příkaz pro výstup konstanty či proměnné (obecně výsledku nějakého výrazu) se samozřejmě v jednotlivých skriptovacích jazycích může lišit, ať již jménem příslušné funkce, tak i konkrétním způsobem zápisu; viz například rozdíl mezi javascriptovskou syntaxí:
print("Hello")
a syntaxí používanou v Closure (Lisp):
(print "Hello")
Této metodě se ve formě řetězce předá libovolný výraz (jehož syntaxe se většinou ani nekontroluje) ve formě řetězce a metoda vrátí tvar korektního příkazu, kterým je možné tento výraz ve vybraném skriptovacím jazyce vytisknout na standardní výstup a/nebo konzoli integrovaného vývojového prostředí. Obsah výsledného řetězce je samozřejmě závislý na tom, který skriptovací jazyk je použit.
Podobným způsobem pracuje metoda ScriptEngineFactory.getMethodCallSyntax(), která pro zadané jméno objektu (řetězec), jméno metody (taktéž řetězec) a seznam parametrů vrátí syntakticky korektní volání této metody i se všemi předanými parametry. Poslední z těchto podpůrných metod nabízených rozhraním ScriptEngineFactory je metoda ScriptEngineFactory.getProgram(), která na základě zadané posloupnosti příkazů (opět předaných ve formě řetězců) vrátí syntakticky korektní reprezentaci skriptu, který tyto příkazy zavolá – teprve zde se například za jednotlivé příkazy vloží v případě JavaScriptu středníky. Podívejme se na demonstrační příklad, kde jsou všechny tři výše zmíněné metody využity:
import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; /** * Ukazka pouziti metod: * <ul> * <li>ScriptEngineFactory.getOutputStatement()</li> * <li>ScriptEngineFactory.getMethodCallSyntax()</li> * <li>ScriptEngineFactory.getProgram()</li> * </ul> * * @author Pavel Tisnovsky */ public class ScriptingTest6 { /** * Test metody ScriptEngineFactory.getOutputStatement() */ private static void getOutputStatementTest(ScriptEngineFactory factory) { System.out.println(factory.getOutputStatement("Hello world")); } /** * Test metody ScriptEngineFactory.getMethodCallSyntax() */ private static void getMethodCallSyntaxTest(ScriptEngineFactory factory) { System.out.println(factory.getMethodCallSyntax("Math", "atan2", "x", "y")); } /** * Test metody ScriptEngineFactory.getProgram() */ private static void getProgramTest(ScriptEngineFactory factory) { System.out.println(factory.getProgram("let a=10", "a=a+1", "print(a)")); } /** * Inicializace a spusteni testu. */ private static void runTests() { ScriptEngineManager engineManager = new ScriptEngineManager(); ScriptEngine scriptEngine = engineManager.getEngineByName("JavaScript"); ScriptEngineFactory factory = scriptEngine.getFactory(); getOutputStatementTest(factory); getMethodCallSyntaxTest(factory); getProgramTest(factory); } public static void main(String[] args) { runTests(); } }
Po spuštění tohoto demonstračního příkladu v JRE dodávaného s IcedTea6–1.8 získáme následující výstup (který by však neměl být diametrálně odlišný ani na dalších variantách JRE):
print("Hello world") Math.atan2(x,y) let a=10;a=a+1;print(a);
3. Chování javovských objektů v JavaScriptu či dalších skriptovacích jazycích
V předchozí části tohoto seriálu jsme si taktéž velmi stručně řekli, jak lze spustit program napsaný v JavaScriptu, i to, jak je možné tomuto programu předat parametry, popř. jak může program (funkce) napsaný v JavaScriptu vrátit objekt prakticky libovolného typu jako svoji návratovou hodnotu. Ovšem tato problematika není tak jednoduchá, jak by se při pohledu na aplikační programové rozhraní definované v JSR 223 mohlo na první pohled zdát :-) Možné problémy nastávají především ve chvíli, kdy je jako skriptovací jazyk zvolen takový programovací jazyk, který používá dynamické typování, tj. datové typy jsou při běhu skriptu přiřazovány přímo k hodnotám a nikoli k proměnným, což je oproti staticky typované Javě velký rozdíl – nikoli syntaktický, ale zejména sémantický. Navíc je v mnoha skriptovacích jazycích funkce chápána jako plnohodnotný datový typ, takže je možné funkce předávat jako parametry jiným funkcím, vracet funkce jako návratovou hodnotu, přiřazovat funkce do proměnných, atributů objektů (properties) atd.
Na začátku tohoto seriálu [1] [2] bylo uvedeno, že podobná funkcionalita (zejména chápání funkcí jako plnohodnotných objektů) je do JDK zaváděna v rámci projektu Lambda, ovšem na její stabilizaci a rozšíření si budeme muset ještě chvíli počkat (JDK 8?). Mezi úlohy prováděné skrytě prakticky každým skriptovacím enginem tedy patří i konverze a vůbec vyhodnocování datových typů a taktéž správné určení toho, které metody javovských objektů se mají zavolat ve chvíli, kdy se jedná o metody přetížené. Zajímavé je, že skriptovací engine tuto činnost provádí výhradně v čase běhu aplikace, kdy využívá například reflexi, na rozdíl od samotné Javy, u níž se některé (ne všechny!) kontroly a konverze mohou provádět již v době překladu programu do bajtkódu. V následujících třech demonstračních příkladech si některé možnosti nabízené skriptovacím enginem Rhino ukážeme. Bude se jednat o zjištění všech viditelných atributů a metod libovolného javovského objektu a volání metod tohoto objektu, včetně zjednodušeného způsobu volání setterů a getterů.
4. Druhý demonstrační příklad – výpis všech vlastností javovského objektu
V následujícím demonstračním příkladu je ukázáno, že skriptovací engine skutečně vyhodnocuje typy objektů i jejich vlastnosti (properties) až v čase běhu aplikace. Tento příklad je v podstatě velmi jednoduchý: funkci printAllObjectProperties napsané v JavaScriptu je předán jakýkoli objekt vytvořený buď v Javě nebo přímo v JavaScriptu a tato funkce následně vypíše všechny viditelné atributy a metody tohoto objektu (ty se v JavaScriptu nazývají properties; jedná se o položky uložené v asociativním poli, kterým je objekt implementován). Povšimněte si, že v tomto případě není příliš rozlišováno mezi atributy a metodami, což však koresponduje s tím, co jsme si již řekli v předchozí kapitole – funkce a tím pádem i metody (=metody s implicitním parametrem this/self) jsou „pouze“ dalším plnohodnotným datovým typem (používání properties z JavaScriptu je tedy v tomto ohledu jednodušší, než reflection API v Javě :-).
V JavaScriptu je dokonce možné získat i „hodnotu“ celého objektu, což vede k volání metody toString(), u níž je zaručeno, že vždy existuje, protože je děděna již z třídy Object. Následuje výpis zdrojového kódu dnešního druhého demonstračního příkladu, k jehož úspěšnému překladu a spuštění je navíc nutné přeložit i pomocnou třídu TestClass7.java, jejíž zdrojový kód je umístěn pod zdrojovým kódem příkladu:
import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; /** * Vypis vsech viditelnych atributu a metod javovskeho * objektu z JavaScriptu. * * @author Pavel Tisnovsky */ public class ScriptingTest7 { /** * Zavolani javascriptove funkce, ktera vypise seznam * vsech viditelnych atributu a metod objektu, ktery * je funkci predan jako parametr. */ private static void objectPropertiesTest(ScriptEngine engine) throws ScriptException, NoSuchMethodException { final String script = // pomocna funkce, ktera od sebe // vizualne oddelu jednotlive vypisy "function horizontalBreak() {" + " for (i = 0; i<40; i++) {" + " print('-');" + " }" + " println('');" + "}" + // funkce pro vypis vsech properties // objektu, ktery je ji predan jako // parametr "function printAllObjectProperties(object) {" + " println('Object.toString(): ' + object);" + " for (var prop in object) {" + " println('Property: ' + prop);" + " }" + " horizontalBreak();" + "}"; engine.eval(script); // Metoda invokeFunction() se musi volat pres rozhrani Invocable. Invocable invocable = (Invocable) engine; invocable.invokeFunction("printAllObjectProperties", new Object()); invocable.invokeFunction("printAllObjectProperties", new TestClass7()); invocable.invokeFunction("printAllObjectProperties", new StringBuffer()); invocable.invokeFunction("printAllObjectProperties", 42); invocable.invokeFunction("printAllObjectProperties", new java.util.Date()); } /** * Inicializace a spusteni testu. */ private static void runTests() { ScriptEngineManager engineManager = new ScriptEngineManager(); ScriptEngine scriptEngine = engineManager.getEngineByName("JavaScript"); try { objectPropertiesTest(scriptEngine); } catch (ScriptException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } public static void main(String[] args) { runTests(); } }
Zdrojový kód pomocné třídy TestClass7.java:
/** * Pomocna testovaci trida pouzita testem * ScriptingTest7 */ public class TestClass7 { // Atributy s ruznymi pristupovymi pravy @SuppressWarnings("unused") private int privateAttribute; protected int protectedAttribute; int packageProtectedAttribute; public int publicAttribute; // Metody s ruznymi pristupovymi pravy @SuppressWarnings("unused") private void privateMethod() { } protected void protectedMethod() { } void packageProtectedMethod() { } public void publicMethod() { } /** * Tato metoda je mj. pouzita i v JavaScriptu * pri tisku retezcove podoby objektu. */ @Override public String toString() { return "This is TestClass7"; } }
Zajímavé je zjistit, které metody a atributy jsou skutečně po spuštění příkladu vypsány. Jako malý úkol se pokuste odhadnout, proč jsou vypsány jen metody a atributy s viditelností public a jaké to má důsledky například pro bezpečnost aplikací:
Object.toString(): java.lang.Object@a401c2 Property: notifyAll Property: toString Property: equals Property: class Property: wait Property: hashCode Property: getClass Property: notify ---------------------------------------- Object.toString(): This is TestClass7 Property: notifyAll Property: toString Property: equals Property: class Property: wait Property: publicMethod Property: hashCode Property: publicAttribute Property: getClass Property: notify ---------------------------------------- Object.toString(): Property: getChars Property: capacity Property: insert Property: codePointBefore Property: indexOf Property: setCharAt Property: notifyAll Property: length Property: trimToSize Property: reverse Property: charAt Property: subSequence Property: equals Property: notify Property: codePointAt Property: class Property: ensureCapacity Property: chars Property: appendCodePoint Property: wait Property: deleteCharAt Property: toString Property: hashCode Property: lastIndexOf Property: append Property: codePointCount Property: delete Property: offsetByCodePoints Property: setLength Property: replace Property: substring Property: getClass ---------------------------------------- Object.toString(): 42 ---------------------------------------- Object.toString(): Tue Apr 19 22:22:38 CEST 2011 Property: setHours Property: month Property: getHours Property: toString Property: year Property: wait Property: hours Property: getMinutes Property: toLocaleString Property: getClass Property: setSeconds Property: hashCode Property: class Property: seconds Property: notify Property: getTime Property: getDay Property: setTime Property: getDate Property: setDate Property: clone Property: day Property: equals Property: getTimezoneOffset Property: getYear Property: setYear Property: setMinutes Property: before Property: getSeconds Property: after Property: timezoneOffset Property: minutes Property: time Property: notifyAll Property: date Property: compareTo Property: setMonth Property: toGMTString Property: getMonth ----------------------------------------
5. Třetí demonstrační příklad – základní způsob volání getterů a setterů
Dnešní třetí demonstrační příklad vlastně neukazuje nic nového. V příkladu jsou vytvořeny dva skripty obsahující funkce s jedním parametrem, pomocí něhož je javascriptovým funkcím předán objekt vytvořený v Javě. Funkce ve skriptu bez jakékoli kontroly (která by se musela provádět až v čase běhu aplikace, například kontrolou existence properties a jejich typu) zavolá setter a getter pro objekt, u nějž se předpokládá, že je instancí třídy TestClass8. U objektu, který by měl být instancí třídy java.awt.Color se zavolají gettery getRed(), getGreen(), getBlue() a getAlpha(). Ve skutečnosti nejsou předpoklady o typech objektů uvedené v předchozích dvou větách zcela korektní, protože v JavaScriptu postačuje, aby byl oběma funkcím předán libovolný objekt, který má implementovány všechny uvedené settery a gettery a nemusí se nutně jednat o instance tříd TestClass8 a java.awt.Color:
import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; /** * Test, zda je mozne v javascriptovem programu volat settery * a gettery pomoci nasledujici syntaxe: * <pre> * object.getXXX() * object.setXXX(newValue) * </pre> * * @author Pavel Tisnovsky */ public class ScriptingTest8 { /** * Zavolani javascriptove funkce, jejimz parametrem * je instance tridy TestClass8. */ private static void methodCallTest(ScriptEngine engine) throws ScriptException, NoSuchMethodException { final String script = "function callMethods(object) {" + " println('Object.toString(): ' + object);" + " println('old value: ' + object.getX());" + " object.setX(42);" + " println('new value: ' + object.getX());" + "}"; engine.eval(script); ((Invocable)engine).invokeFunction("callMethods", new TestClass8()); } /** * Zavolani nekterych getteru instance tridy jawa.awt.Color * z javascriptu. */ private static void gettersTest(ScriptEngine engine) throws ScriptException, NoSuchMethodException { final String script = "function callColorGetters() {" + " var color = new java.awt.Color(0x123456);" + " println('Object.toString(): ' + color);" + " println('red: ' + color.getRed());" + " println('blue: ' + color.getBlue());" + " println('green: ' + color.getGreen());" + " println('alpha: ' + color.getAlpha());" + "}"; engine.eval(script); // Metoda invokeFunction() se musi volat pres rozhrani Invocable. ((Invocable)engine).invokeFunction("callColorGetters"); } /** * Inicializace a spusteni testu. */ private static void runTests() { ScriptEngineManager engineManager = new ScriptEngineManager(); ScriptEngine scriptEngine = engineManager.getEngineByName("JavaScript"); try { methodCallTest(scriptEngine); System.out.println("----------------------------------"); gettersTest(scriptEngine); } catch (ScriptException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } public static void main(String[] args) { runTests(); } }
Pro správnou funkci tohoto demonstračního příkladu je nutné přeložit i pomocnou třídu TestClass8, která obsahuje příslušné settery i gettery, které jsou z příkladu volány:
/** * Pomocna testovaci trida pouzita testy * ScriptingTest8 a ScriptingTest9 */ public class TestClass8 { private int x = 0; public void setX(int x) { System.out.println("Setter called with parameter " + x); this.x = x; } public int getX() { System.out.println("Getter called, returning value " + this.x); return this.x; } /** * Tato metoda je mj. pouzita i v JavaScriptu * pri tisku retezcove podoby objektu. */ @Override public String toString() { return "This is TestClass8 containing attribute: " + this.x; } }
Tento demonstrační příklad po svém spuštění vypíše na standardní výstup následující informace:
Object.toString(): This is TestClass8 containing attribute: 0 Getter called, returning value 0 old value: 0 Setter called with parameter 42 Getter called, returning value 42 new value: 42 ---------------------------------- Object.toString(): java.awt.Color[r=18,g=52,b=86] red: 18 blue: 86 green: 52 alpha: 255
6. Čtvrtý demonstrační příklad – zjednodušený způsob volání getterů a setterů
Předchozí demonstrační příklad byl v tomto článku uveden především jako ukázka základního způsobu, jakým lze přistupovat k setterům a getterům v JavaScriptu syntakticky prakticky shodným způsobem, jako je tomu v samotné Javě. Ovšem javascriptoví programátoři mají k dispozici ještě jeden způsob, který je jednodušší a pro mnohé vývojáře i čitelnější. Namísto volání objekt.getX() či objekt.setX(..) lze totiž v JavaScriptu použít taktéž následující dvě možnosti: objekt[‚x‘] a objekt.x (což jsou sémanticky stejné výrazy), kde za x lze doplnit jméno setteru či getteru bez předpony „set“ či „get“, přičemž se první písmeno názvu setteru/getteru změní na malé.
Předpokladem pro správnou činnost těchto příkazů je to, aby objekt neobsahoval viditelný atribut stejného jména, což by však při korektním programování v Javě nastat vůbec nemělo :-) Ostatně to, že se ve všech čtyřech případech (objekt.getX(), objekt.setX(), objekt[‚x‘] a objekt.x) skutečně volají gettery a settery, lze jednoduše ověřit – postačuje změnit jméno nastavovaného či čteného atributu, popř. do setterů a getterů přidat ladicí informace, což je i náš případ:
import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; /** * Test, zda je mozne v javascriptovem programu volat settery * a gettery objektu vytvorenych v Jave pomoci nasledujici syntaxe: * <pre> * var foo = objekt['atribut']; * objekt['atribut'] = 'bar'; * var foo = objekt.atribut; * objekt.atribut = 'bar'; * </pre> * * @author Pavel Tisnovsky */ public class ScriptingTest9 { /** * Zavolani javascriptove funkce, jejimz parametrem * je instance tridy TestClass8. */ private static void methodCallTest(ScriptEngine engine) throws ScriptException, NoSuchMethodException { final String script = "function callMethods(object) {" + " println('Object.toString(): ' + object);" + " println('old value: ' + object.x);" + " object.x = 42;" + " println('new value: ' + object.x);" + "}"; engine.eval(script); // Metoda invokeFunction() se musi volat pres rozhrani Invocable. ((Invocable)engine).invokeFunction("callMethods", new TestClass8()); } /** * Zavolani nekterych getteru instance tridy jawa.awt.Color * z javascriptu. */ private static void gettersTest(ScriptEngine engine) throws ScriptException, NoSuchMethodException { final String script = "function callColorGetters() {" + " var color = new java.awt.Color(0x123456);" + " println('Object.toString(): ' + color);" + " println('red: ' + color['red']);" + " println('blue: ' + color['blue']);" + " println('green: ' + color['green']);" + " println('alpha: ' + color['alpha']);" + " println('red: ' + color.red);" + " println('blue: ' + color.blue);" + " println('green: ' + color.green);" + " println('alpha: ' + color.alpha);" + "}"; engine.eval(script); // Metoda invokeFunction() se musi volat pres rozhrani Invocable. ((Invocable)engine).invokeFunction("callColorGetters"); } /** * Inicializace a spusteni testu. */ private static void runTests() { ScriptEngineManager engineManager = new ScriptEngineManager(); ScriptEngine scriptEngine = engineManager.getEngineByName("JavaScript"); try { methodCallTest(scriptEngine); System.out.println("----------------------------------"); gettersTest(scriptEngine); } catch (ScriptException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } public static void main(String[] args) { runTests(); } }
Tento demonstrační program po svém spuštění vypíše prakticky ty stejné informace, jako demonstrační program předchozí, pouze se opakují informace získané pomocí getterů nad objektem Color (protože jsou gettery volané dvakrát, pokaždé s jinou syntaxí zápisu):
Object.toString(): This is TestClass8 containing attribute: 0 Getter called, returning value 0 old value: 0 Setter called with parameter 42 Getter called, returning value 42 new value: 42 ---------------------------------- Object.toString(): java.awt.Color[r=18,g=52,b=86] red: 18 blue: 86 green: 52 alpha: 255 red: 18 blue: 86 green: 52 alpha: 255
7. Pátý demonstrační příklad – JavaScript a přetížené metody v javovském objektu
V dnešním pátém (v celkovém pořadí osmém :-) demonstračním příkladu je ukázáno chování enginu Rhino při rozhodování o tom, která přetížená metoda se má zavolat z JavaScriptu. V tomto příkladu je využita pomocná třída TestClass10 obsahující přetíženou a viditelnou metodu nazvanou overloaded, která je volána ze skriptu s různými typy parametrů. Komentář k chování enginu Rhino bude uveden pod zdrojovými kódy:
import java.awt.Color; import java.util.Date; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class ScriptingTest10 { private static void overloadedMethodCallTest(ScriptEngine scriptEngine) throws ScriptException, NoSuchMethodException { final String script = "function accessJavaObject(object) {" + " object.overloaded(true);" + " object.overloaded(false);" + " object.overloaded(object == null);" + " object.overloaded(new java.lang.Boolean(true));" + " object.overloaded(new java.lang.Boolean(false));" + " object.overloaded(new java.lang.Boolean(object == null));" + " object.overloaded(new java.util.Date());" + " object.overloaded(new Date());" + " object.overloaded(new java.awt.Color(0));" + " object.overloaded('Hello world');" + " object.overloaded(42);" + " object.overloaded(1/3.0);" + " object.overloaded(new java.awt.Frame());" + "}"; scriptEngine.eval(script); ((Invocable)scriptEngine).invokeFunction("accessJavaObject", new TestClass10()); } private static Object callOverloadedMethod(ScriptEngine scriptEngine, Object value) throws ScriptException, NoSuchMethodException { return ((Invocable)scriptEngine).invokeFunction("valueReturnedFromMethod", new TestClass10(), value); } private static void overloadedMethodCallTest2(ScriptEngine scriptEngine) throws ScriptException, NoSuchMethodException { final String script = "function valueReturnedFromMethod(object, value) {" + " return object.overloaded(value);" + "}"; scriptEngine.eval(script); System.out.println(callOverloadedMethod(scriptEngine, 42)); System.out.println(callOverloadedMethod(scriptEngine, 1.0/3)); System.out.println(callOverloadedMethod(scriptEngine, true)); System.out.println(callOverloadedMethod(scriptEngine, Boolean.valueOf(true))); System.out.println(callOverloadedMethod(scriptEngine, new Boolean(true))); System.out.println(callOverloadedMethod(scriptEngine, new Date())); System.out.println(callOverloadedMethod(scriptEngine, new Color(0x123456))); System.out.println(callOverloadedMethod(scriptEngine, new StringBuffer("hello world"))); } /** * Inicializace a spusteni testu. */ private static void runTests() { ScriptEngineManager engineManager = new ScriptEngineManager(); ScriptEngine scriptEngine = engineManager.getEngineByName("JavaScript"); try { overloadedMethodCallTest(scriptEngine); System.out.println("---------------------------------"); overloadedMethodCallTest2(scriptEngine); } catch (ScriptException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } public static void main(String[] args) { runTests(); } }
Pomocná třída TestClass10 má následující obsah:
import java.awt.Color; import java.util.Date; /** * Pomocna testovaci trida pouzita testem * ScriptingTest10 */ public class TestClass10 { public String overloaded(Object o) { System.out.println("overloaded(object) called with parameter "+ o); return "Object"; } public String overloaded(String o) { System.out.println("overloaded(string) called with parameter " + o); return "String"; } public String overloaded(int o) { System.out.println("overloaded(int) called with parameter " + o); return "Integer"; } public String overloaded(double o) { System.out.println("overloaded(double) called with parameter " + o); return "Double"; } public String overloaded(Date o) { System.out.println("overloaded(Date) called with parameter " + o); return "Date"; } public String overloaded(Color o) { System.out.println("overloaded(Color) called with parameter " + o); return "Color"; } public String overloaded(boolean o) { System.out.println("overloaded(boolean) called with parameter " + o); return "boolean"; } public String overloaded(Boolean o) { System.out.println("overloaded(Boolean) called with parameter " + o); return "Boolean"; } @Override public String toString() { return "This is TestClass"; } }
8. Komentář k výsledkům předchozího demonstračního příkladu
Výsledky vytištěné po spuštění předchozího demonstračního příkladu jsou v několika ohledech zajímavé. Především je vidět, že skriptovací engine dokáže rozlišit mezi primitivním datovým typem boolean a příslušnou „obalovou“ třídou Boolean. Taktéž se korektně provede změna javascriptového objektu Date na typ java.util.Date, ovšem na druhou stranu se v použité verzi skriptovacího enginu všechny číselné proměnné převádí na typ double (popř. na obalovou třídu Double), což znamená, že se nezavolá metoda overloaded(int), a to ani tehdy, když je při volání použita celočíselná konstanta:
overloaded(boolean) called with parameter true overloaded(boolean) called with parameter false overloaded(boolean) called with parameter false overloaded(Boolean) called with parameter true overloaded(Boolean) called with parameter false overloaded(Boolean) called with parameter false overloaded(Date) called with parameter Tue Apr 19 23:01:35 CEST 2011 overloaded(Date) called with parameter Tue Apr 19 23:01:35 CEST 2011 overloaded(Color) called with parameter java.awt.Color[r=0,g=0,b=0] overloaded(string) called with parameter Hello world overloaded(double) called with parameter 42.0 overloaded(double) called with parameter 0.3333333333333333 overloaded(object) called with parameter java.awt.Frame[frame0,0,0,0x0,invalid,hidden,layout=java.awt.BorderLayout,title=,resizable,normal] --------------------------------- overloaded(double) called with parameter 42.0 Double overloaded(double) called with parameter 0.3333333333333333 Double overloaded(boolean) called with parameter true boolean overloaded(boolean) called with parameter true boolean overloaded(boolean) called with parameter true boolean overloaded(Date) called with parameter Tue Apr 19 23:01:35 CEST 2011 Date overloaded(Color) called with parameter java.awt.Color[r=18,g=52,b=86] Color overloaded(object) called with parameter hello world Object
9. Odkazy na Internetu
- JSRs: Java Specification Requests – JSR 223: Scripting for the Java Platform
http://www.jcp.org/en/jsr/detail?id=223 - Scripting for the Java Platform
http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/ - Scripting for the Java Platform (Wikipedia)
http://en.wikipedia.org/wiki/Scripting_for_the_Java_Platform - Java Community Process
http://en.wikipedia.org/wiki/Java_Specification_Request - Package javax.script (JavaDoc)
http://download.oracle.com/javase/6/docs/api/javax/script/package-summary.html - javax.script.Bindings
http://download.oracle.com/javase/6/docs/api/javax/script/Bindings.html - javax.script.Compilable
http://download.oracle.com/javase/6/docs/api/javax/script/Compilable.html - javax.script.Invocable
http://download.oracle.com/javase/6/docs/api/javax/script/Invocable.html - javax.script.ScriptContext
http://download.oracle.com/javase/6/docs/api/javax/script/ScriptContext.html - javax.script.ScriptEngine
http://download.oracle.com/javase/6/docs/api/javax/script/ScriptEngine.html - javax.script.ScriptEngineFactory
http://download.oracle.com/javase/6/docs/api/javax/script/ScriptEngineFactory.html - javax.script.AbstractScriptEngine
http://download.oracle.com/javase/6/docs/api/javax/script/AbstractScriptEngine.html - javax.script.CompiledScript
http://download.oracle.com/javase/6/docs/api/javax/script/CompiledScript.html - javax.script.ScriptEngineManager
http://download.oracle.com/javase/6/docs/api/javax/script/ScriptEngineManager.html - javax.script.SimpleBindings
http://download.oracle.com/javase/6/docs/api/javax/script/SimpleBindings.html - javax.script.SimpleScriptContext
http://download.oracle.com/javase/6/docs/api/javax/script/SimpleScriptContext.html - javax.script.ScriptException
http://download.oracle.com/javase/6/docs/api/javax/script/ScriptException.html - The Java Compatibility Test Tools: JavaTest Harness
http://java.sun.com/developer/technicalArticles/JCPtools2/ - JavaScript engine (Wikipedia)
http://en.wikipedia.org/wiki/JavaScript_engine - Rhino (JavaScript engine)
http://en.wikipedia.org/wiki/Rhino_(JavaScript_engine) - Rhino: JavaScript for Java
http://www.mozilla.org/rhino/ - Java HotSpot VM Options
http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html - HugePages
http://linux-mm.org/HugePages - Tuning big java heap and linux huge pages
http://www.tikalk.com/alm/forums/tuning-big-java-heap-and-linux-huge-pages - How do I set up hugepages in Red Hat Enterprise Linux 4
http://magazine.redhat.com/2007/05/29/how-do-i-set-up-hugepages-in-red-hat-enterprise-linux-4/ - Java SE Tuning Tip: Large Pages on Windows and Linux
http://blogs.sun.com/dagastine/entry/java_se_tuning_tip_large - Translation lookaside buffer
http://en.wikipedia.org/wiki/Translation_lookaside_buffer - Physical Address Extension
http://en.wikipedia.org/wiki/Physical_Address_Extension - Java HotSpot VM Options
http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html - Amdahl's law
http://en.wikipedia.org/wiki/Amdahl_law - Garbage collection (computer science)
http://en.wikipedia.org/wiki/Garbage_collection_(computer_science) - Dr. Dobb's | G1: Java's Garbage First Garbage Collector
http://www.drdobbs.com/article/printableArticle.jhtml?articleId=219401061&dept_url=/java/ - Java's garbage-collected heap
http://www.javaworld.com/javaworld/jw-08–1996/jw-08-gc.html - Compressed oops in the Hotspot JVM
http://wikis.sun.com/display/HotSpotInternals/CompressedOops - 32-bit or 64-bit JVM? How about a Hybrid?
http://blog.juma.me.uk/2008/10/14/32-bit-or-64-bit-jvm-how-about-a-hybrid/ - Compressed object pointers in Hotspot VM
http://blogs.sun.com/nike/entry/compressed_object_pointers_in_hotspot - Java HotSpot™ Virtual Machine Performance Enhancements
http://download.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html - Using jconsole
http://download.oracle.com/javase/1.5.0/docs/guide/management/jconsole.html - jconsole – Java Monitoring and Management Console
http://download.oracle.com/javase/1.5.0/docs/tooldocs/share/jconsole.html - Great Computer Language Shootout
http://c2.com/cgi/wiki?GreatComputerLanguageShootout - x86–64
http://en.wikipedia.org/wiki/X86–64 - Physical Address Extension
http://en.wikipedia.org/wiki/Physical_Address_Extension - Java performance
http://en.wikipedia.org/wiki/Java_performance - 1.6.0_14 (6u14)
http://www.oracle.com/technetwork/java/javase/6u14–137039.html?ssSourceSiteId=otncn - Update Release Notes
http://www.oracle.com/technetwork/java/javase/releasenotes-136954.html - Java virtual machine: 4.10 Limitations of the Java Virtual Machine
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#88659 - Java™ Platform, Standard Edition 7 Binary Snapshot Releases
http://dlc.sun.com.edgesuite.net/jdk7/binaries/index.html - Trying the prototype
http://mail.openjdk.java.net/pipermail/lambda-dev/2010-August/002179.html - Better closures (for Java)
http://blogs.sun.com/jrose/entry/better_closures - Lambdas in Java: An In-Depth Analysis
http://www.infoq.com/articles/lambdas-java-analysis - Class ReflectiveOperationException
http://download.java.net/jdk7/docs/api/java/lang/ReflectiveOperationException.html - Proposal: Indexing access syntax for Lists and Maps
http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/001108.html - Proposal: Elvis and Other Null-Safe Operators
http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/000047.html - Java 7 : Oracle pushes a first version of closures
http://www.baptiste-wicht.com/2010/05/oracle-pushes-a-first-version-of-closures/ - Groovy: An agile dynamic language for the Java Platform
http://groovy.codehaus.org/Operators - Better Strategies for Null Handling in Java
http://www.slideshare.net/Stephan.Schmidt/better-strategies-for-null-handling-in-java - Control Flow in the Java Virtual Machine
http://www.artima.com/underthehood/flowP.html - Java Virtual Machine
http://en.wikipedia.org/wiki/Java_virtual_machine - ==, .equals(), compareTo(), and compare()
http://leepoint.net/notes-java/data/expressions/22compareobjects.html - New JDK7 features
http://openjdk.java.net/projects/jdk7/features/ - Project Coin: Bringing it to a Close(able)
http://blogs.sun.com/darcy/entry/project_coin_bring_close - ClosableFinder source code
http://blogs.sun.com/darcy/resource/ProjectCoin/CloseableFinder.java - Joe Darcy blog about JDK
http://blogs.sun.com/darcy - Java 7 – more dynamics
http://www.baptiste-wicht.com/2010/04/java-7-more-dynamics/ - ArrayList (JDK 1.4)
http://download.oracle.com/javase/1.4.2/docs/api/java/util/ArrayList.html