< prev index next >

modules/javafx.fxml/src/main/java/javafx/fxml/FXMLLoader.java

Print this page
@@ -61,10 +61,12 @@
  import javafx.util.Builder;
  import javafx.util.BuilderFactory;
  import javafx.util.Callback;
  
  import javax.script.Bindings;
+ import javax.script.Compilable;
+ import javax.script.CompiledScript;
  import javax.script.ScriptContext;
  import javax.script.ScriptEngine;
  import javax.script.ScriptEngineManager;
  import javax.script.ScriptException;
  import javax.script.SimpleBindings;

@@ -1556,42 +1558,94 @@
                          }
  
                          location = new URL(FXMLLoader.this.location, source);
                      }
                      Bindings engineBindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
-                     engineBindings.put(engine.FILENAME, location.getPath());
+                     String filename = location.getPath();
+                     engineBindings.put(engine.FILENAME, filename);
  
                      InputStreamReader scriptReader = null;
+                     String script=null;
                      try {
                          scriptReader = new InputStreamReader(location.openStream(), charset);
-                         engine.eval(scriptReader);
-                     } catch(ScriptException exception) {
-                         exception.printStackTrace();
+                         StringBuilder sb = new StringBuilder();
+                         final int bufSize = 4096;
+                         char[] charBuffer = new char[bufSize];
+                         int n;
+                         do {
+                             n = scriptReader.read(charBuffer,0,bufSize);
+                             if (n > 0) {
+                                 sb.append(new String(charBuffer,0,n));
+                           }
+                         } while (n > -1);
+                         script = sb.toString();
+                     } catch (IOException exception) {
+                         throw constructLoadException(exception);
                      } finally {
                          if (scriptReader != null) {
                              scriptReader.close();
                          }
                      }
-                 } catch (IOException exception) {
-                     throw constructLoadException(exception);
+                     try {
+                         if (engine instanceof Compilable && compileScript) {
+                             CompiledScript compiledScript = null;
+                             try {
+                                 compiledScript=((Compilable) engine).compile(script);
+                             } catch (ScriptException compileExc) {
+                                 Logging.getJavaFXLogger().warning(filename + ": compiling caused \"" + compileExc +
+                                     "\", falling back to evaluating script in uncompiled mode");
+                             }
+                             if (compiledScript != null) {
+                                 compiledScript.eval();
+                             } else { // fallback to uncompiled mode
+                                 engine.eval(script);
+                             }
+                         } else {
+                             engine.eval(script);
+                         }
+                     } catch (ScriptException exception) {
+                         System.err.println(filename + ": caused ScriptException");
+                         exception.printStackTrace();
+                     }
+                 }
+                 catch (IOException exception) {
+                   throw constructLoadException(exception);
                  }
              }
          }
  
          @Override
          public void processEndElement() throws IOException {
              super.processEndElement();
  
              if (value != null && !staticLoad) {
                  // Evaluate the script
+                 String filename = null;
                  try {
                      Bindings engineBindings = scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE);
-                     engineBindings.put(scriptEngine.FILENAME, location.getPath() + "-script_starting_at_line_"
-                                        + (getLineNumber() - (int) ((String) value).codePoints().filter(c -> c == '\n').count()));
-                     scriptEngine.eval((String)value);
+                     String script = (String) value;
+                     filename = location.getPath() + "-script_starting_at_line_"
+                                        + (getLineNumber() - (int) script.codePoints().filter(c -> c == '\n').count());
+                     engineBindings.put(scriptEngine.FILENAME, filename);
+                     if (scriptEngine instanceof Compilable && compileScript) {
+                         CompiledScript compiledScript = null;
+                         try {
+                             compiledScript=((Compilable) scriptEngine).compile(script);
+                         } catch (ScriptException compileExc) {
+                             Logging.getJavaFXLogger().warning(filename + ": compiling caused \"" + compileExc +
+                                 "\", falling back to evaluating script in uncompiled mode");
+                         }
+                         if (compiledScript != null) {
+                             compiledScript.eval();
+                         } else { // fallback to uncompiled mode
+                             scriptEngine.eval(script);
+                         }
+                     } else {
+                         scriptEngine.eval(script);
+                     }
                  } catch (ScriptException exception) {
-                     System.err.println(exception.getMessage());
+                     System.err.println(filename + ": caused ScriptException\n" + exception.getMessage());
                  }
              }
          }
  
          @Override

@@ -1679,15 +1733,28 @@
      // Event handler implemented in script code
      private static class ScriptEventHandler implements EventHandler<Event> {
          public final String script;
          public final ScriptEngine scriptEngine;
          public final String filename;
+         public CompiledScript compiledScript;
+         public boolean isCompiled=false;
  
          public ScriptEventHandler(String script, ScriptEngine scriptEngine, String filename) {
              this.script = script;
              this.scriptEngine = scriptEngine;
              this.filename = filename;
+             if (scriptEngine instanceof Compilable  && compileScript) {
+                 try {
+                     // supply the filename to the scriptEngine engine scope Bindings in case it is needed for compilation
+                     scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE).put(scriptEngine.FILENAME, filename);
+                     this.compiledScript = ((Compilable) scriptEngine).compile(script);
+                     this.isCompiled = true;
+                 } catch (ScriptException compileExc) {
+                     Logging.getJavaFXLogger().warning(filename + ": compiling caused \"" + compileExc +
+                         "\", falling back to evaluating script in uncompiled mode");
+                 }
+             }
          }
  
          @Override
          public void handle(Event event) {
              // Don't pollute the page namespace with values defined in the script

@@ -1697,13 +1764,17 @@
              localBindings.put(EVENT_KEY, event);
              localBindings.put(scriptEngine.ARGV, new Object[]{event});
              localBindings.put(scriptEngine.FILENAME, filename);
              // Execute the script
              try {
-                 scriptEngine.eval(script, localBindings);
-             } catch (ScriptException exception){
-                 throw new RuntimeException(exception);
+                 if (isCompiled) {
+                    compiledScript.eval(localBindings);
+                 } else {
+                    scriptEngine.eval(script, localBindings);
+                 }
+             } catch (ScriptException exception) {
+                 throw new RuntimeException(filename + ": caused ScriptException", exception);
              }
          }
      }
  
      // Observable list change listener

@@ -1817,10 +1888,11 @@
  
      private XMLStreamReader xmlStreamReader = null;
      private Element current = null;
  
      private ScriptEngine scriptEngine = null;
+     private static boolean compileScript = true;
  
      private List<String> packages = new LinkedList<String>();
      private Map<String, Class<?>> classes = new HashMap<String, Class<?>>();
  
      private ScriptEngineManager scriptEngineManager = null;

@@ -1843,10 +1915,16 @@
      /**
       * The tag name of import processing instruction.
       */
      public static final String IMPORT_PROCESSING_INSTRUCTION = "import";
  
+     /**
+      * The tag name of the compile processing instruction.
+      * @since 15
+      */
+     public static final String COMPILE_PROCESSING_INSTRUCTION = "compile";
+ 
      /**
       * Prefix of 'fx' namespace.
       */
      public static final String FX_NAMESPACE_PREFIX = "fx";
      /**

@@ -2676,10 +2754,14 @@
  
          if (piTarget.equals(LANGUAGE_PROCESSING_INSTRUCTION)) {
              processLanguage();
          } else if (piTarget.equals(IMPORT_PROCESSING_INSTRUCTION)) {
              processImport();
+         } else if (piTarget.equals(COMPILE_PROCESSING_INSTRUCTION)) {
+             String strCompile=xmlStreamReader.getPIData().trim();
+             // if PIData() is empty string then default to true, otherwise use Boolean.parseBoolean(string) to determine the boolean value
+             compileScript = (strCompile.length()==0 ? true : Boolean.parseBoolean(strCompile));
          }
      }
  
      private void processLanguage() throws LoadException {
          if (scriptEngine != null) {
< prev index next >