Προγραμματισμός

JavaScript σε Java

Η πρόσφατη ανάρτηση JavaLobby Οι κορυφαίες 10 αχρησιμοποίητες δυνατότητες στην Java ήταν εξαιρετικά δημοφιλής. Τη στιγμή αυτής της γραφής, είναι η κορυφαία θέση στην κατηγορία DZone Top Links. Επιπλέον, δημοσιεύτηκε επίσης μια απάντηση σε αυτό. Υπάρχουν πολλές ενδιαφέρουσες παρατηρήσεις σχετικά με τις μη χρησιμοποιούμενες λειτουργίες στην Java και στις δύο αναρτήσεις ιστολογίων και συμφωνώ με μερικά περισσότερα από άλλα. Ωστόσο, ένα στοιχείο που πραγματικά τράβηξε την προσοχή μου ήταν ο ισχυρισμός ότι το Java SE 6 είναι ένα από τα πιο αχρησιμοποίητα χαρακτηριστικά Java.

Μου αρέσει πολύ να δουλεύω με το Java SE 6 και έχω γράψει ή έχω κάνει blog στο Java SE 6 πολλές φορές στο παρελθόν. Σε αυτήν την ανάρτηση ιστολογίου, σκοπεύω να δείξω ένα μέρος της ικανότητας Java SE 6 να φιλοξενεί εκτέλεση κώδικα JavaScript.

Οι περισσότεροι προγραμματιστές Java και προγραμματιστές JavaScript κατανοούν ότι εκτός από τα τέσσερα γράμματα "J-A-V-A", η JavaScript και η Java έχουν πολύ λίγα κοινά στοιχεία εκτός από κάποια κληρονομιά τύπου C. Ωστόσο, μπορεί μερικές φορές να είναι χρήσιμο να εκτελείται μια γλώσσα δέσμης ενεργειών από τον κώδικα Java και το Java SE 6 το επιτρέπει.

Το πακέτο javax.script παρουσιάστηκε με το Java SE 6 και περιλαμβάνει κλάσεις, διεπαφές και μια ελεγμένη εξαίρεση που σχετίζεται με τη χρήση μηχανών δέσμης ενεργειών εντός Java. Αυτή η δημοσίευση ιστολογίου θα επικεντρωθεί στα ScriptEngineFactory, ScriptEngineManager, ScriptEngine και ScriptException.

Ένα από τα πρώτα πράγματα που μπορεί να θέλει να κάνει είναι να προσδιορίσει ποιες μηχανές δέσμης ενεργειών είναι ήδη διαθέσιμες. Το επόμενο απόσπασμα κώδικα δείχνει πόσο εύκολο είναι να γίνει αυτό με το Java SE 6.

τελικό ScriptEngineManager manager = νέο ScriptEngineManager (); για (final ScriptEngineFactory scriptEngine: manager.getEngineFactories ()) {System.out.println (scriptEngine.getEngineName () + "(" + scriptEngine.getEngineVersion () + ")"); System.out.println ("\ tLanguage:" + scriptEngine.getLanguageName () + "(" + scriptEngine.getLanguageVersion () + ")"); System.out.println ("\ t Κοινά ονόματα / ψευδώνυμα:"); για (final String engineAlias: scriptEngine.getNames ()) {System.out.println (engineAlias ​​+ ""); }} 

Ο κωδικός που εμφανίζεται παραπάνω δημιουργεί έξοδο όπως αυτή που εμφανίζεται στο επόμενο στιγμιότυπο οθόνης.

Όπως δείχνει αυτή η εικόνα, ο κινητήρας JavaScript Mozilla Rhino περιλαμβάνεται στο Sun's Java SE 6. Βλέπουμε επίσης ορισμένα "κοινά ονόματα" που σχετίζονται με αυτόν τον συγκεκριμένο κινητήρα. Οποιοδήποτε από αυτά τα ονόματα μπορεί να χρησιμοποιηθεί για την αναζήτηση αυτής της μηχανής. Σε μεταγενέστερα παραδείγματα σε αυτήν την ανάρτηση, θα χρησιμοποιήσω το κοινό όνομα "js" για αυτήν την αναζήτηση.

Το επόμενο δείγμα κώδικα θα εκμεταλλευτεί την παρεχόμενη μηχανή Rhino JavaScript για την εκτέλεση κάποιου κώδικα JavaScript από κώδικα Java. Σε αυτήν την περίπτωση, θα εκμεταλλευτούμε τη συνάρτηση JavaScript toExponential.

 / ** * Γράψτε τον αριθμό σε εκθετική μορφή. * * @param numberToWriteInExponentialForm Ο αριθμός που θα αναπαρασταθεί σε * εκθετική μορφή. * @param numberDecimalPlaces Ο αριθμός των δεκαδικών ψηφίων που θα χρησιμοποιηθούν στην * εκθετική αναπαράσταση. * / public static void writeNumberAsExponential (final number numberToWriteInExponentialForm, final int numberDecimalPlaces) {final ScriptEngine engine = manager.getEngineByName ("js"); δοκιμάστε το {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 αντιμετώπισε προσπαθώντας να γράψει εκθετικό:" + scriptException.toString ()); }} 

Ο παραπάνω κώδικας καλεί απευθείας τη JavaScript χρησιμοποιώντας τη μέθοδο ScriptEngine.eval (String) για την αξιολόγηση της παρεχόμενης συμβολοσειράς που περιέχει σύνταξη JavaScript. Πριν από την επίκληση του κακ μέθοδος, δύο παράμετροι "μεταβιβάζονται" (δεσμευμένες) στον κώδικα JavaScript μέσω κλήσεων ScriptEngine.put (String, Object). Το αντικείμενο αποτελέσματος της εκτελεσμένης JavaScript έχει πρόσβαση στον κώδικα Java χρησιμοποιώντας μια κλήση ScriptEngine.get (String).

Για να δείξετε τον παραπάνω κώδικα χρησιμοποιώντας το toExponential συνάρτηση, θα χρησιμοποιήσω τον ακόλουθο κωδικό "πελάτη".

τελικό 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 μπορεί να υποβληθεί σε επεξεργασία με κώδικα παρόμοιο με αυτόν που εμφανίζεται στη συνέχεια.

 / ** * Επεξεργαστείτε το σενάριο JavaScript που μεταβιβάστηκε που θα πρέπει να περιλαμβάνει μια αντιστοίχιση * σε μια μεταβλητή με το όνομα που ορίζεται από το παρεχόμενο όνομαOfOutput και * μπορεί να περιλαμβάνει παραμέτρους που ορίζονται από inputParameters * * @param javaScriptCodeToProcess Η συμβολοσειρά που περιέχει κώδικα JavaScript προς * θα αξιολογηθεί. Αυτή η συμβολοσειρά δεν έχει ελεγχθεί για κανένα είδος εγκυρότητας και * ενδέχεται να οδηγήσει στη ρίψη ενός ScriptException, το οποίο θα * καταγράφηκε. * @param nameOfOutput Το όνομα της μεταβλητής εξόδου που σχετίζεται με το * παρεχόμενο σενάριο JavaScript. * @param inputParameters Προαιρετικός χάρτης των ονομάτων παραμέτρων σε τιμές παραμέτρων * που μπορεί να χρησιμοποιηθεί στο παρεχόμενο σενάριο JavaScript. Αυτός ο χάρτης * μπορεί να είναι μηδενικός εάν δεν αναμένονται παράμετροι εισαγωγής στο σενάριο. * / public static Object processArbitraryJavaScript (final String javaScriptCodeToProcess, final String nameOfOutput, final Map inputParameters) {Object result = null; τελικό ScriptEngine engine = manager.getEngineByName ("js"); δοκιμάστε το {if (inputParameters! = null) {για (τελική παράμετρο Map.Entry: inputParameters.entrySet ()) {engine.put (parameter.getKey (), parameter.getValue ()); }} engine.eval (javaScriptCodeToProcess); αποτέλεσμα = engine.get (nameOfOutput); } catch (ScriptException scriptException) {LOGGER.severe ("Το ScriptException αντιμετώπισε την προσπάθεια εγγραφής αυθαίρετου JavaScript '" + javaScriptCodeToProcess + "':" + scriptException.toString ()); } αποτέλεσμα επιστροφής; } 

Ο παραπάνω κώδικας παρέχει αρκετή ευελιξία όσον αφορά τη JavaScript που μπορεί να υποβληθεί σε επεξεργασία. Αυτή πιθανώς δεν είναι η καλύτερη ιδέα για τον κώδικα παραγωγής, αλλά διευκολύνει την απόδειξη της χρήσης διαφόρων λειτουργιών JavaScript εντός της Java.

Το πρώτο παράδειγμα για τη χρήση αυτής της σχετικά αυθαίρετης επεξεργασίας JavaScript εκμεταλλεύεται το αντικείμενο Date της JavaScript. Το δείγμα κώδικα εμφανίζεται στη συνέχεια.

 System.out.println ("Today's Date:" + processArbitraryJavaScript ("var date = new Date (); var month = (date.getMonth () + 1) .toFixed (0)", "μήνας", 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 = νέο HashMap (); exponentParameters.put ("βάση", 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 εάν το παρεχόμενο String είναι null. Ο κώδικας που χρησιμοποιείται για την επιβολή σφάλματος σεναρίου εμφανίζεται στη συνέχεια.

 / ** * Προκαλεί εσκεμμένα σφάλμα χειρισμού σεναρίων για να δείξει τον τύπο πληροφοριών * που περιλαμβάνει το ScriptException. * / 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. Άλλες μηχανές δέσμης ενεργειών μπορούν επίσης να συσχετιστούν με την Java, αλλά είναι βολικό να διαθέτουμε έναν εκτός συσκευασίας με το Mozilla Rhino.

Πλήρες στιγμιότυπο οθόνης και εξόδου οθόνης

Για πληρότητα, συμπεριλαμβάνω την πλήρη λίστα κωδικών σε ένα μέρος εδώ και την προκύπτουσα έξοδο μετά από αυτό.

JavaScriptInJavaExample.java