Programmering

JavaScript i Java

Det nylige JavaLobby-innlegget De 10 beste ubrukt funksjonene i Java har vært ekstremt populært. I skrivende stund er det det topprangerte innlegget i DZone Top Links-kategorien. I tillegg er det også lagt ut et svar på det. Det er mange interessante observasjoner om underutnyttede funksjoner i Java i begge blogginnleggene, og jeg er enig med noen mer enn andre. Imidlertid var det som virkelig fanget oppmerksomheten min påstanden om at Java SE 6 er en av de mest ubrukte Java-funksjonene.

Jeg liker veldig godt å jobbe med Java SE 6 og har skrevet om eller blogget på Java SE 6-funksjoner flere ganger tidligere. I dette blogginnlegget har jeg tenkt å demonstrere en del av Java SE 6s evne til å være vert for å utføre JavaScript-kode.

De fleste Java-utviklere og JavaScript-utviklere forstår at foruten de fire bokstavene "J-A-V-A", har JavaScript og Java veldig lite til felles annet enn noen C-lignende arv. Likevel kan det til tider være nyttig å kjøre et skriptspråk fra Java-kode, og Java SE 6 tillater dette.

Pakken javax.script ble introdusert med Java SE 6 og inkluderer klasser, grensesnitt og et kontrollert unntak relatert til bruk av skriptmotorer i Java. Dette blogginnlegget vil fokusere på ScriptEngineFactory, ScriptEngineManager, ScriptEngine og ScriptException.

En av de første tingene man kanskje vil gjøre er å bestemme hvilke skriptmotorer som allerede er tilgjengelige. Neste kodebit viser hvor enkelt dette er å gjø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 ("\ tFelles navn / aliaser:"); for (final String engineAlias: scriptEngine.getNames ()) {System.out.println (engineAlias ​​+ ""); }} 

Koden vist ovenfor genererer utdata som vist i neste skjermbilde.

Som dette bildet viser, er Mozilla Rhino JavaScript-motoren inkludert i Suns Java SE 6. Vi ser også noen "vanlige navn" som er knyttet til denne motoren. Alle disse navnene kan brukes til å slå opp denne motoren. I senere eksempler i dette innlegget vil jeg bruke det vanlige navnet "js" for denne oppslaget.

Neste kodeeksempel vil dra nytte av den medfølgende Rhino JavaScript-motoren for å utføre noe JavaScript-kode fra Java-kode. I dette tilfellet vil vi dra nytte av JavaScript's toExponential-funksjonen.

 / ** * Skriv nummer i eksponentiell form. * * @param numberToWriteInExponentialForm Tallet som skal representeres i * eksponentiell form. * @param numberDecimalPlaces Antall desimaler som skal brukes i * eksponentiell representasjon. * / public static void writeNumberAsExponential (final Number numberToWriteInExponentialForm, final int numberDecimalPlaces) {final ScriptEngine engine = manager.getEngineByName ("js"); prøv {engine.put ("inputNumber", numberToWriteInExponentialForm); engine.put ("desimalPlaces", 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 oppstått når du prøver å skrive eksponentiell:" + scriptException.toString ()); }} 

Koden ovenfor påkaller JavaScript direkte ved hjelp av ScriptEngine.eval (String) -metoden for å evaluere den angitte String som inneholder JavaScript-syntaks. Før påkallelse av eval metode, blir to parametere "sendt inn" (bundet) til JavaScript-koden via ScriptEngine.put (String, Object) -anrop. Resultatobjektet til det utførte JavaScript er tilgjengelig i Java-koden ved hjelp av en ScriptEngine.get (String) -anrop.

For å demonstrere ovennevnte kode ved hjelp av toExponential funksjon, bruker 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 koden ovenfor kjøres mot writeNumberAsExponential-metoden som er vist tidligere og JavaScript brukes, ser utgangen ut som den som vises i neste skjermbilde.

Dette eksemplet er nok til å demonstrere hvor enkelt det er å påkalle JavaScript-funksjonalitet fra Java SE 6. Dette kan imidlertid implementeres enda mer generisk som de to neste eksemplene vil demonstrere. Det første eksemplet viser påkalling av relativt vilkårlig JavaScript uten parametere som er sendt / bundet, og det andre eksemplet viser påkallelse av relativt vilkårlig JavaScript med parametere som er sendt / bundet.

En relativt vilkårlig JavaScript-streng kan behandles med kode som ligner på den som vises neste.

 / ** * Behandle det innsendte JavaScript-skriptet som skal inneholde en oppgave * til en variabel med navnet som er foreskrevet av det oppgitte navnetOfOutput og * kan inneholde parametere som er foreskrevet av inputParameters. * * @param javaScriptCodeToProcess Strengen som inneholder JavaScript-kode som skal * evalueres. Denne strengen er ikke sjekket for noen form for gyldighet, og * kan muligens føre til at et ScriptException kastes, som * vil bli logget. * @param nameOfOutput Navnet på utdatavariabelen som er tilknyttet JavaScript-skriptet *. * @param inputParameters Valgfritt kart over parameternavn til parameterverdier * som kan brukes i det medfølgende JavaScript-skriptet. Dette kartet * kan være null hvis det ikke forventes noen inndataparametere i skriptet. * / public static Object processArbitraryJavaScript (final String javaScriptCodeToProcess, final String nameOfOutput, final Map inputParameters) {Objektresultat = null; endelig ScriptEngine engine = 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); } catch (ScriptException scriptException) {LOGGER.severe ("ScriptException oppstått ved å prøve å skrive vilkårlig JavaScript '" + javaScriptCodeToProcess + "':" + scriptException.toString ()); } returnere resultat; } 

Koden ovenfor gir ganske mye fleksibilitet når det gjelder JavaScript som kan behandles. Dette er sannsynligvis ikke den beste ideen for produksjonskode, men gjør det lettere å demonstrere bruk av forskjellige JavaScript-funksjoner i Java.

Det første eksemplet som bruker denne relativt vilkårlige JavaScript-behandlingen, utnytter JavaScript-objektet Date. Eksempelkoden vises neste.

 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 koden spesifiserer at en JavaScript-dato skal hentes (som vil være den gjeldende datoen), og at den måneden, månedsdatoen og hele året skal hentes fra den øyeblikkelige datoen. Utgangen for dette vises neste.

Det siste eksemplet arbeidet med en vilkårlig JavaScript-streng, men brukte ingen parametere. Det neste eksemplet viser tilveiebringelse av parametere til denne vilkårlige behandlingen av JavaScript-streng da den demonstrerer bruken av JavaScript-funksjonen. Koden for dette eksemplet er oppført neste.

 final Map exponentParameters = new 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)); 

Resultatet fra å kjøre dette eksemplet vises i følgende skjermbilde.

For mitt siste eksempel på dette blogginnlegget demonstrerer jeg standarden toString () utdata fra ScriptException erklært i noen av de foregående eksemplene. De ScriptEngine.eval metoden kaster dette avmerkede unntaket hvis det er en feil i å utføre / evaluere det medfølgende skriptet. Denne metoden kaster også et NullPointerException hvis den angitte strengen er null. Koden som brukes til å tvinge en skriptfeil vises neste.

 / ** * Gjør bevisst at skripthåndteringsfeil viser typen informasjon * som et ScriptException inkluderer. * / public static void testScriptExceptionHandling () {System.out.println (processArbitraryJavaScript ("Garbage In", "none", null)); } 

Denne koden gir et meningsløst skript (når det gjelder JavaScript-syntaks), men det er akkurat det som trengs for å demonstrere ScriptException.toString (), som kalles som en del av unntakshåndteringen i metoden vist ovenfor for å håndtere en vilkårlig JavaScript-streng . Når koden kjøres, ser vi unntaksinformasjonen som vist i neste bilde.

Den delen av produksjonen som kommer fra ScriptException.toString () er den delen som sier: "javax.script.ScriptException: sun.org.mozilla.javascript.internal.EvaluatorException: missing; before statement (# 1) in at line number 1."

De ScriptException inneholder filnavnet, linjenummeret og kolonnenummeret til unntaket, noe som er spesielt nyttig hvis en fil med JavaScript-kode er gitt for evaluering.

Konklusjon

Java SE 6 gjør det enkelt å bruke JavaScript i Java-kode. Andre skriptmotorer kan også assosieres med Java, men det er praktisk å ha en leveres utenom boksen med Mozilla Rhino.

Komplett øyeblikksbilde av kode og utgangsskjerm

For fullstendighet inkluderer jeg den komplette kodelisten på ett sted her og den resulterende produksjonen etter det.

JavaScriptInJavaExample.java

$config[zx-auto] not found$config[zx-overlay] not found