• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TAKETODAY / today-infrastructure / 18154768944

01 Oct 2025 07:26AM UTC coverage: 81.882% (-0.005%) from 81.887%
18154768944

push

github

web-flow
Merge pull request #290 from TAKETODAY/dev/jspecify

jspecify

59788 of 78013 branches covered (76.64%)

Branch coverage included in aggregate %.

141239 of 167496 relevant lines covered (84.32%)

3.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

46.38
today-context/src/main/java/infra/scripting/support/StandardScriptEvaluator.java
1
/*
2
 * Copyright 2017 - 2025 the original author or authors.
3
 *
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see [https://www.gnu.org/licenses/]
16
 */
17

18
package infra.scripting.support;
19

20
import org.jspecify.annotations.Nullable;
21

22
import java.io.IOException;
23
import java.util.Map;
24

25
import javax.script.Bindings;
26
import javax.script.ScriptEngine;
27
import javax.script.ScriptEngineManager;
28
import javax.script.ScriptException;
29

30
import infra.beans.factory.BeanClassLoaderAware;
31
import infra.core.io.Resource;
32
import infra.scripting.ScriptCompilationException;
33
import infra.scripting.ScriptEvaluator;
34
import infra.scripting.ScriptSource;
35
import infra.util.CollectionUtils;
36
import infra.util.StringUtils;
37

38
/**
39
 * {@code javax.script} (JSR-223) based implementation of Framework's {@link ScriptEvaluator}
40
 * strategy interface.
41
 *
42
 * @author Juergen Hoeller
43
 * @author Costin Leau
44
 * @author <a href="https://github.com/TAKETODAY">海子 Yang</a>
45
 * @see ScriptEngine#eval(String)
46
 * @since 4.0
47
 */
48
public class StandardScriptEvaluator implements ScriptEvaluator, BeanClassLoaderAware {
49

50
  @Nullable
51
  private String engineName;
52

53
  @Nullable
54
  private volatile Bindings globalBindings;
55

56
  @Nullable
57
  private volatile ScriptEngineManager scriptEngineManager;
58

59
  /**
60
   * Construct a new {@code StandardScriptEvaluator}.
61
   */
62
  public StandardScriptEvaluator() { }
3✔
63

64
  /**
65
   * Construct a new {@code StandardScriptEvaluator} for the given class loader.
66
   *
67
   * @param classLoader the class loader to use for script engine detection
68
   */
69
  public StandardScriptEvaluator(ClassLoader classLoader) {
×
70
    this.scriptEngineManager = new ScriptEngineManager(classLoader);
×
71
  }
×
72

73
  /**
74
   * Construct a new {@code StandardScriptEvaluator} for the given JSR-223
75
   * {@link ScriptEngineManager} to obtain script engines from.
76
   *
77
   * @param scriptEngineManager the ScriptEngineManager (or subclass thereof) to use
78
   */
79
  public StandardScriptEvaluator(ScriptEngineManager scriptEngineManager) {
×
80
    this.scriptEngineManager = scriptEngineManager;
×
81
  }
×
82

83
  /**
84
   * Set the name of the language meant for evaluating the scripts (e.g. "Groovy").
85
   * <p>This is effectively an alias for {@link #setEngineName "engineName"},
86
   * potentially (but not yet) providing common abbreviations for certain languages
87
   * beyond what the JSR-223 script engine factory exposes.
88
   *
89
   * @see #setEngineName
90
   */
91
  public void setLanguage(String language) {
92
    this.engineName = language;
3✔
93
  }
1✔
94

95
  /**
96
   * Set the name of the script engine for evaluating the scripts (e.g. "Groovy"),
97
   * as exposed by the JSR-223 script engine factory.
98
   *
99
   * @see #setLanguage
100
   */
101
  public void setEngineName(String engineName) {
102
    this.engineName = engineName;
3✔
103
  }
1✔
104

105
  /**
106
   * Set the globally scoped bindings on the underlying script engine manager,
107
   * shared by all scripts, as an alternative to script argument bindings.
108
   *
109
   * @see #evaluate(ScriptSource, Map)
110
   * @see ScriptEngineManager#setBindings(Bindings)
111
   * @see javax.script.SimpleBindings
112
   */
113
  public void setGlobalBindings(Map<String, Object> globalBindings) {
114
    Bindings bindings = StandardScriptUtils.getBindings(globalBindings);
×
115
    this.globalBindings = bindings;
×
116
    ScriptEngineManager scriptEngineManager = this.scriptEngineManager;
×
117
    if (scriptEngineManager != null) {
×
118
      scriptEngineManager.setBindings(bindings);
×
119
    }
120
  }
×
121

122
  @Override
123
  public void setBeanClassLoader(ClassLoader classLoader) {
124
    ScriptEngineManager scriptEngineManager = this.scriptEngineManager;
×
125
    if (scriptEngineManager == null) {
×
126
      scriptEngineManager = new ScriptEngineManager(classLoader);
×
127
      this.scriptEngineManager = scriptEngineManager;
×
128
      Bindings bindings = this.globalBindings;
×
129
      if (bindings != null) {
×
130
        scriptEngineManager.setBindings(bindings);
×
131
      }
132
    }
133
  }
×
134

135
  @Override
136
  @Nullable
137
  public Object evaluate(ScriptSource script) {
138
    return evaluate(script, null);
5✔
139
  }
140

141
  @Override
142
  @Nullable
143
  public Object evaluate(ScriptSource script, @Nullable Map<String, Object> argumentBindings) {
144
    ScriptEngine engine = getScriptEngine(script);
4✔
145
    try {
146
      if (CollectionUtils.isEmpty(argumentBindings)) {
3✔
147
        return engine.eval(script.getScriptAsString());
5✔
148
      }
149
      else {
150
        Bindings bindings = StandardScriptUtils.getBindings(argumentBindings);
3✔
151
        return engine.eval(script.getScriptAsString(), bindings);
6✔
152
      }
153
    }
154
    catch (IOException ex) {
×
155
      throw new ScriptCompilationException(script, "Cannot access script for ScriptEngine", ex);
×
156
    }
157
    catch (ScriptException ex) {
×
158
      throw new ScriptCompilationException(script, new StandardScriptEvalException(ex));
×
159
    }
160
  }
161

162
  /**
163
   * Obtain the JSR-223 ScriptEngine to use for the given script.
164
   *
165
   * @param script the script to evaluate
166
   * @return the ScriptEngine (never {@code null})
167
   */
168
  protected ScriptEngine getScriptEngine(ScriptSource script) {
169
    ScriptEngineManager scriptEngineManager = this.scriptEngineManager;
3✔
170
    if (scriptEngineManager == null) {
2!
171
      scriptEngineManager = new ScriptEngineManager();
4✔
172
      this.scriptEngineManager = scriptEngineManager;
3✔
173
    }
174

175
    if (StringUtils.hasText(this.engineName)) {
4✔
176
      return StandardScriptUtils.retrieveEngineByName(scriptEngineManager, this.engineName);
5✔
177
    }
178
    else if (script instanceof ResourceScriptSource) {
3!
179
      Resource resource = ((ResourceScriptSource) script).getResource();
4✔
180
      String extension = StringUtils.getFilenameExtension(resource.getName());
4✔
181
      if (extension == null) {
2!
182
        throw new IllegalStateException(
×
183
                "No script language defined, and no file extension defined for resource: " + resource);
184
      }
185
      ScriptEngine engine = scriptEngineManager.getEngineByExtension(extension);
4✔
186
      if (engine == null) {
2!
187
        throw new IllegalStateException("No matching engine found for file extension '" + extension + "'");
×
188
      }
189
      return engine;
2✔
190
    }
191
    else {
192
      throw new IllegalStateException(
×
193
              "No script language defined, and no resource associated with script: " + script);
194
    }
195
  }
196

197
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc