Programmering

JavaScript i Java

Det nylige JavaLobby-indlæg Top 10 ubrugte funktioner i Java har været ekstremt populært. På tidspunktet for denne skrivning er det det øverste rangerede indlæg i kategorien DZone Top Links. Derudover er der også sendt et svar på det. Der er mange interessante observationer om underudnyttede funktioner i Java i begge blogindlæg, og jeg er enig med nogle mere end andre. En ting, der virkelig fangede min opmærksomhed, var påstanden om, at Java SE 6 er en af ​​de mest ubrugte Java-funktioner.

Jeg nyder virkelig at arbejde med Java SE 6 og har skrevet om eller blogget på Java SE 6-funktioner flere gange tidligere. I dette blogindlæg agter jeg at demonstrere en del af Java SE 6s evne til at være vært for at udføre JavaScript-kode.

De fleste Java-udviklere og JavaScript-udviklere forstår, at foruden de fire bogstaver "J-A-V-A" har JavaScript og Java meget lidt til fælles ud over en eller anden C-lignende arv. Alligevel kan det til tider være nyttigt at køre et script-sprog fra Java-kode, og Java SE 6 tillader dette.

Pakken javax.script blev introduceret med Java SE 6 og inkluderer klasser, grænseflader og en kontrolleret undtagelse relateret til brug af scriptmotorer inden for Java. Denne blogindlæg vil fokusere på ScriptEngineFactory, ScriptEngineManager, ScriptEngine og ScriptException.

En af de første ting, man måske vil gøre, er at bestemme, hvilke scriptmotorer der allerede er tilgængelige. Det næste kodestykke viser, hvor let dette er at gøre med Java SE 6.

endelig ScriptEngineManager manager = ny 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 ​​+ ""); }} 

Koden vist ovenfor genererer output som vist i næste skærmbillede.

Som dette billede viser, er Mozilla Rhino JavaScript-motoren inkluderet i Suns Java SE 6. Vi ser også nogle "almindelige navne", der er knyttet til denne motor. Ethvert af disse navne kan bruges til at slå denne motor op. I senere eksempler i dette indlæg bruger jeg det almindelige navn "js" til denne opslag.

Den næste kodeeksempel drager fordel af den medfølgende Rhino JavaScript-motor til at udføre nogle JavaScript-koder fra Java-koden. I dette tilfælde drager vi fordel af JavaScript's toExponential-funktion.

 / ** * Skriv nummer i eksponentiel form. * * @param numberToWriteInExponentialForm Det nummer, der skal repræsenteres i * eksponentiel form. * @param numberDecimalPlaces Antallet af decimaler, der skal bruges i * eksponentiel repræsentation. * / public static void writeNumberAsExponential (final Number numberToWriteInExponentialForm, final int numberDecimalPlaces) {final ScriptEngine engine = manager.getEngineByName ("js"); prøv {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 ("Nummer:" + eksponentialnummer); } fange (ScriptException scriptException) {LOGGER.severe ("ScriptException stødte på forsøg på at skrive eksponentielt:" + scriptException.toString ()); }} 

Koden ovenfor påberåber JavaScript direkte ved hjælp af ScriptEngine.eval (String) -metoden til at evaluere den medfølgende streng, der indeholder JavaScript-syntaks. Før påkaldelse af eval metode "sendes to parametre" (bundet) til JavaScript-koden via ScriptEngine.put (String, Object) opkald. Resultatobjektet for det udførte JavaScript fås i Java-koden ved hjælp af et ScriptEngine.get (String) -opkald.

For at demonstrere ovenstående kode ved hjælp af toExponential funktion, bruger jeg følgende "klient" -kode.

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

Når ovenstående kode køres mod metoden writeNumberAsExponential, der er vist tidligere, og JavaScript er anvendt, ser outputen ud som den, der vises i næste skærmbillede.

Dette eksempel er nok til at demonstrere, hvor let det er at påberåbe JavaScript-funktionalitet fra Java SE 6. Dette kan dog implementeres endnu mere generisk, som de næste to eksempler viser. Det første eksempel viser påkaldelse af relativt vilkårlig JavaScript uden parametre, der er videregivet / bundet, og det andet eksempel viser påkaldelse af relativt vilkårlig JavaScript med videregående / bundet parametre.

En relativt vilkårlig JavaScript-streng kan behandles med kode svarende til den næste.

 / ** * Behandl det indleverede JavaScript-script, der skal indeholde en tildeling * til en variabel med navnet foreskrevet af det angivne navnOfOutput og * kan omfatte parametre, der er foreskrevet af inputParameters. * * @param javaScriptCodeToProcess Strengen, der indeholder JavaScript-kode, der skal * evalueres. Denne streng kontrolleres ikke for nogen form for gyldighed og * kan muligvis føre til kaste af en ScriptException, som ville blive * logget. * @param nameOfOutput Navnet på outputvariablen, der er knyttet til det * leverede JavaScript-script. * @param inputParameters Valgfri kort over parameternavne til parameterværdier *, der muligvis anvendes i det medfølgende JavaScript-script. Dette kort * kan være nul, hvis der ikke forventes nogen inputparametre i scriptet. * / public static Object processArbitraryJavaScript (final String javaScriptCodeToProcess, final String nameOfOutput, final Map inputParameters) {Objektresultat = null; endelig ScriptEngine-motor = manager.getEngineByName ("js"); prøv {if (inputParameters! = null) {for (final Map.Entry parameter: inputParameters.entrySet ()) {engine.put (parameter.getKey (), parameter.getValue ()); }} engine.eval (javaScriptCodeToProcess); resultat = engine.get (nameOfOutput); } fange (ScriptException scriptException) {LOGGER.severe ("ScriptException stødte på forsøg på at skrive vilkårlig JavaScript '" + javaScriptCodeToProcess + "':" + scriptException.toString ()); } returnere resultat } 

Koden ovenfor giver en hel del fleksibilitet med hensyn til JavaScript, der kan behandles. Dette er sandsynligvis ikke den bedste idé til produktionskode, men gør det nemmere at demonstrere brugen af ​​forskellige JavaScript-funktioner inden for Java.

Det første eksempel på at bruge denne relativt vilkårlige JavaScript-behandling udnytter JavaScript's Date-objekt. Eksempelkoden vises derefter.

 System.out.println ("Dagens dato:" + 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)); 

Denne kode angiver, at en JavaScript-dato skal hentes (som vil være den aktuelle dato), og at den måned, dato på måneden og hele året skal udvindes fra den øjeblikkelige dato. Outputtet til dette vises derefter.

Det sidste eksempel arbejdede på en vilkårlig JavaScript-streng, men brugte ingen parametre. Det næste eksempel viser tilvejebringelse af parametre til denne vilkårlige JavaScript-strengbehandling, da det demonstrerer brugen af ​​JavaScript's pow-funktion. Koden til dette eksempel vises derefter.

 endelig Map exponentParameters = ny HashMap (); exponentParameters.put ("base", 2); exponentParameters.put ("eksponent", 5); System.out.println ("2 til 5 er:" + processArbitraryJavaScript ("var svar = Math.pow (base, eksponent)", "svar", exponentParameters)); 

Outputtet fra at køre dette eksempel vises i følgende skærmbillede.

For mit sidste eksempel på dette blogindlæg demonstrerer jeg standarden toString () output af ScriptException erklæret i nogle af de tidligere eksempler. Det ScriptEngine.eval metode kaster denne afkrydsede undtagelse, hvis der er en fejl i udførelse / evaluering af det medfølgende script. Denne metode kaster også en NullPointerException, hvis den angivne streng er nul. Koden, der bruges til at tvinge en scriptfejl, vises derefter.

 / ** * Forsætligt medføre, at scripthåndteringsfejl viser den type information *, som en ScriptException inkluderer. * / public static void testScriptExceptionHandling () {System.out.println (processArbitraryJavaScript ("Garbage In", "none", null)); } 

Denne kode giver et meningsløst script (med hensyn til JavaScript-syntaks), men det er præcis det, der er nødvendigt for at demonstrere ScriptException.toString (), der kaldes som en del af undtagelseshåndteringen i metoden vist ovenfor til håndtering af en vilkårlig JavaScript-streng . Når koden udføres, ser vi undtagelsesoplysningerne som vist i det næste billede.

Den del af output, der kommer fra ScriptException.toString () er den del, der siger: "javax.script.ScriptException: sun.org.mozilla.javascript.internal.EvaluatorException: missing; before statement (# 1) in at line number 1."

Det ScriptException indeholder undtagelsens filnavn, linjenummer og kolonnenummer, hvilket er særligt nyttigt, hvis en fil med JavaScript-kode leveres til evaluering.

Konklusion

Java SE 6 gør det nemt at bruge JavaScript inden for Java-kode. Andre scriptmotorer kan også tilknyttes Java, men det er praktisk at have en leveret out-of-the-box med Mozilla Rhino.

Komplet kode og output skærmbillede snapshot

For fuldstændighed inkluderer jeg den komplette kodeliste et sted her og den resulterende output efter det.

JavaScriptInJavaExample.java