Skip to content

Commit 9fae270

Browse files
authored
Trim runtime deps: make Nashorn optional, bulk up JS filter tests (#1775)
Slim htsjdk's published runtime classpath by making the JavaScript engine an opt-in dependency, and clean up around the change. Net effect for consumers of the v5.0.0 artifact: 6 fewer jars on the runtime classpath (nashorn-core + 5 ASM transitives, ~2.5 MB) and one less "misleading direct dependency" in the published POM. ** BREAKING CHANGE ** Consumers using htsjdk.samtools.filter.JavascriptSamRecordFilter or htsjdk.variant.variantcontext.filter.JavascriptVariantFilter must now add a JSR-223 "js" engine to their own runtime classpath. The recommended choice is OpenJDK Nashorn: Gradle: runtimeOnly 'org.openjdk.nashorn:nashorn-core:15.7' Maven: <dependency> <groupId>org.openjdk.nashorn</groupId> <artifactId>nashorn-core</artifactId> <version>15.7</version> <scope>runtime</scope> </dependency> If no engine is on the classpath at runtime, AbstractJavascriptFilter's constructor now throws a RuntimeScriptException whose message names the calling filter class and prints both Gradle and Maven coordinates, so the failure is fully self-describing. The breaking change will be called out in the dedicated v5.0.0 CHANGELOG / breaking-changes PR alongside the other v5.0.0 changes.
1 parent 49e50e3 commit 9fae270

10 files changed

Lines changed: 523 additions & 117 deletions

File tree

build.gradle

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,30 @@ jacocoTestReport {
4444

4545
dependencies {
4646
implementation 'com.fulcrumgenomics:jlibdeflate:0.1.0'
47-
implementation 'commons-logging:commons-logging:1.3.0'
4847
implementation "org.xerial.snappy:snappy-java:1.1.10.5"
4948
implementation 'org.apache.commons:commons-compress:1.26.0'
5049
implementation 'org.tukaani:xz:1.9'
5150
implementation "org.json:json:20231013"
52-
implementation 'org.openjdk.nashorn:nashorn-core:15.4'
53-
51+
52+
// commons-jexl 2.1.1 pulls commons-logging:1.1.1 (released 2007). htsjdk has no direct
53+
// need for commons-logging itself, so we publish a version constraint rather than a real
54+
// dependency: it kicks in only if commons-logging is pulled transitively, and bumps it to
55+
// a maintained version. Drop this if commons-jexl is ever upgraded past 2.1.1.
56+
constraints {
57+
implementation('commons-logging:commons-logging:1.3.0') {
58+
because 'jexl 2.1.1 pulls commons-logging 1.1.1 transitively; pin a maintained version'
59+
}
60+
}
61+
62+
// Nashorn is the JSR-223 "js" engine used by the optional JavaScript filter classes
63+
// (htsjdk.samtools.filter.JavascriptSamRecordFilter, htsjdk.variant.variantcontext.filter.JavascriptVariantFilter).
64+
// It's compileOnly so downstream consumers who don't use those filter classes don't pay the
65+
// cost of nashorn-core + 5 ASM artifacts on their runtime classpath. Consumers who do use
66+
// them must add nashorn-core to their own runtime classpath; see the error message thrown
67+
// by AbstractJavascriptFilter when no JS engine is found.
68+
compileOnly 'org.openjdk.nashorn:nashorn-core:15.7'
69+
testImplementation 'org.openjdk.nashorn:nashorn-core:15.7'
70+
5471
api "org.apache.commons:commons-jexl:2.1.1"
5572

5673
testImplementation 'org.testng:testng:7.8.0'

src/main/java/htsjdk/samtools/filter/AbstractJavascriptFilter.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,7 @@ protected AbstractJavascriptFilter(final Reader scriptReader, final HEADER heade
8585
final ScriptEngine engine = manager.getEngineByName("js");
8686
if (engine == null) {
8787
CloserUtil.close(scriptReader);
88-
throw new RuntimeScriptException("The embedded 'javascript' engine is not available in java. "
89-
+ "Do you use the SUN/Oracle Java Runtime ?");
88+
throw new RuntimeScriptException(noJsEngineMessage(this.getClass().getSimpleName()));
9089
}
9190
if (scriptReader == null) {
9291
throw new RuntimeScriptException("missing ScriptReader.");
@@ -109,6 +108,30 @@ protected AbstractJavascriptFilter(final Reader scriptReader, final HEADER heade
109108
this.bindings.put(DEFAULT_HEADER_KEY, header);
110109
}
111110

111+
static String noJsEngineMessage(final String filterClassName) {
112+
return String.join(
113+
"\n",
114+
"No JSR-223 JavaScript engine (lookup name \"js\") was found on the classpath.",
115+
"",
116+
"Starting with htsjdk 5.0.0, htsjdk no longer ships a JavaScript engine as a runtime",
117+
"dependency, so that consumers who do not use the JavaScript filter classes do not pay",
118+
"the cost of carrying ~6 extra jars (nashorn-core plus its ASM transitives, ~2.5 MB).",
119+
"",
120+
"To use " + filterClassName + ", add a JSR-223-compatible JavaScript engine to your",
121+
"runtime classpath. The recommended choice is OpenJDK Nashorn:",
122+
"",
123+
" Gradle: runtimeOnly 'org.openjdk.nashorn:nashorn-core:15.7'",
124+
"",
125+
" Maven: <dependency>",
126+
" <groupId>org.openjdk.nashorn</groupId>",
127+
" <artifactId>nashorn-core</artifactId>",
128+
" <version>15.7</version>",
129+
" <scope>runtime</scope>",
130+
" </dependency>",
131+
"",
132+
"Any other JSR-223 engine that registers under the name \"js\" will also work.");
133+
}
134+
112135
/** return a javascript engine as a Compilable */
113136
private static Compilable getCompilable(final ScriptEngine engine) {
114137
if (!(engine instanceof Compilable)) {

src/main/java/htsjdk/samtools/filter/JavascriptSamRecordFilter.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,26 @@
3030
import java.io.Reader;
3131

3232
/**
33-
* javascript based read filter
33+
* JavaScript-based {@link SamRecordFilter}.
3434
*
35+
* <p>The user-supplied script is evaluated against each {@link SAMRecord} with the following
36+
* variables in scope:
3537
*
36-
* The script puts the following variables in the script context:
38+
* <ul>
39+
* <li>{@code record} - the {@link SAMRecord} being evaluated</li>
40+
* <li>{@code header} - the {@link SAMFileHeader} associated with the reader</li>
41+
* </ul>
3742
*
38-
* - 'record' a SamRecord (
39-
* https://github.com/samtools/htsjdk/blob/master/src/java/htsjdk/samtools/
40-
* SAMRecord.java ) - 'header' (
41-
* https://github.com/samtools/htsjdk/blob/master/src/java/htsjdk/samtools/
42-
* SAMFileHeader.java )
43+
* <p>Example: keep only records with mapping quality >= 30:
44+
* <pre>{@code
45+
* new JavascriptSamRecordFilter("record.getMappingQuality() >= 30;", header)
46+
* }</pre>
47+
*
48+
* <p><b>Runtime requirement:</b> as of htsjdk 5.0.0, htsjdk does not ship a JavaScript engine as
49+
* a runtime dependency. To use this class, add a JSR-223-compatible JavaScript engine
50+
* (e.g. {@code org.openjdk.nashorn:nashorn-core}) to your runtime classpath. If no engine is
51+
* available, the constructor throws a {@link htsjdk.samtools.util.RuntimeScriptException} whose
52+
* message lists the dependency coordinates.
4353
*
4454
* @author Pierre Lindenbaum PhD Institut du Thorax - INSERM - Nantes - France
4555
*/

src/main/java/htsjdk/variant/variantcontext/filter/JavascriptVariantFilter.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,26 @@
3131
import java.io.Reader;
3232

3333
/**
34-
* javascript based variant filter The script puts the following variables in
35-
* the script context:
34+
* JavaScript-based {@link VariantContextFilter}.
3635
*
37-
* - 'header' a htsjdk.variant.vcf.VCFHeader
38-
* - 'variant' a htsjdk.variant.variantcontext.VariantContext
36+
* <p>The user-supplied script is evaluated against each {@link VariantContext} with the following
37+
* variables in scope:
38+
*
39+
* <ul>
40+
* <li>{@code variant} - the {@link VariantContext} being evaluated</li>
41+
* <li>{@code header} - the {@link VCFHeader} associated with the reader</li>
42+
* </ul>
43+
*
44+
* <p>Example: keep only variants on chromosome 1:
45+
* <pre>{@code
46+
* new JavascriptVariantFilter("variant.getContig() == '1';", header)
47+
* }</pre>
48+
*
49+
* <p><b>Runtime requirement:</b> as of htsjdk 5.0.0, htsjdk does not ship a JavaScript engine as
50+
* a runtime dependency. To use this class, add a JSR-223-compatible JavaScript engine
51+
* (e.g. {@code org.openjdk.nashorn:nashorn-core}) to your runtime classpath. If no engine is
52+
* available, the constructor throws a {@link htsjdk.samtools.util.RuntimeScriptException} whose
53+
* message lists the dependency coordinates.
3954
*
4055
* @author Pierre Lindenbaum PhD Institut du Thorax - INSERM - Nantes - France
4156
*/

0 commit comments

Comments
 (0)