Getting `ScriptException` when using Kotlin `ScriptEngine` in tests run from Maven - java

In a Maven project I have tests that are using the Kotlin ScriptEngine (just calling scriptEngine.eval(script)). When I run the tests from IntelliJ they all pass, but during runs of mvn test, I am getting the following error:
javax.script.ScriptException: Cannot access script base class 'kotlin.script.experimental.jsr223.KotlinJsr223DefaultScript'. Check your module classpath for missing or conflicting dependencies
Cannot access script provided property class 'kotlin.script.experimental.jvmhost.jsr223.KotlinJsr223ScriptEngineImpl'. Check your module classpath for missing or conflicting dependencies
Cannot access script provided property class 'org.jetbrains.kotlin.cli.common.repl.AggregatedReplStageState'. Check your module classpath for missing or conflicting dependencies
I have these three classes in the classpath via appropriate Maven dependencies. (I actually added a call to System.out.println(KotlinJsr223DefaultScript.class.getName()) in the failing tests to make sure it's the case.) Here's the relevant fragment of the dependency tree:
[INFO] | \- org.jetbrains.kotlin:kotlin-scripting-jsr223:jar:1.3.72:compile
[INFO] | +- org.jetbrains.kotlin:kotlin-script-runtime:jar:1.3.72:compile
[INFO] | +- org.jetbrains.kotlin:kotlin-scripting-common:jar:1.3.72:compile
[INFO] | | \- org.jetbrains.kotlinx:kotlinx-coroutines-core:jar:1.2.1:compile
[INFO] | +- org.jetbrains.kotlin:kotlin-scripting-jvm:jar:1.3.72:compile
[INFO] | +- org.jetbrains.kotlin:kotlin-scripting-jvm-host:jar:1.3.72:compile
[INFO] | | \- org.jetbrains.intellij.deps:trove4j:jar:1.0.20181211:runtime
[INFO] | +- org.jetbrains.kotlin:kotlin-scripting-compiler:jar:1.3.72:compile
[INFO] | | +- org.jetbrains.kotlin:kotlin-scripting-js:jar:1.3.72:compile
[INFO] | | +- org.jetbrains.kotlin:kotlin-util-klib:jar:1.3.72:compile
[INFO] | | | \- org.jetbrains.kotlin:kotlin-util-io:jar:1.3.72:compile
[INFO] | | \- org.jetbrains.kotlin:kotlin-scripting-compiler-impl:jar:1.3.72:compile
[INFO] | +- org.jetbrains.kotlin:kotlin-compiler:jar:1.3.72:runtime
[INFO] | \- org.jetbrains.kotlin:kotlin-reflect:jar:1.3.72:runtime
I saw people on the Internet run into similar issues, but their solution was to make sure the classes are available on the classpath, which I already have.

I was able to get the unit tests to work on the command line. The issue was the surefire plugin that would use a manifest-only jar that would contain the classpath. For some reason, the order in which the jars were listed in that manifest-only jar caused the issues that OP describes above. I was able to fix this issue by setting surefire.useManifestOnlyJar=false, either in pom.xml
<properties>
<surefire.useManifestOnlyJar>false</surefire.useManifestOnlyJar>
</properties>
or as command line argument for Maven:
mvn -Dsurefire.useManifestOnlyJar=false test
For more details on that property, see
mvn surefire:help -Ddetail=true
This resolves the problem for me.
There is also documentation on class loading with surefire: https://maven.apache.org/surefire/maven-surefire-plugin/examples/class-loading.html

Related

Maven: How to update transitive dependency (snakeyaml)?

I scanned my Spring Boot app using Synk and there are some vulnerabilities after scan. For this reason, I needed to update snakeyaml, but as far as I know, it is a dependency below spring-boot-starter-web.
Here is the dependency tree for my project:
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.7.5:compile
[INFO] | +- org.springframework.boot:spring-boot-starter:jar:2.7.5:compile
[INFO] | | +- org.springframework.boot:spring-boot-starter-logging:jar:2.7.5:compile
[INFO] | | | +- ch.qos.logback:logback-classic:jar:1.2.11:compile
[INFO] | | | | \- ch.qos.logback:logback-core:jar:1.2.11:compile
[INFO] | | | +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.17.2:compile
[INFO] | | | | \- org.apache.logging.log4j:log4j-api:jar:2.17.2:compile
[INFO] | | | \- org.slf4j:jul-to-slf4j:jar:1.7.36:compile
[INFO] | | +- jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile
[INFO] | | \- org.yaml:snakeyaml:jar:1.30:compile
In this scene, how can I update snakeyaml? Should I add a remove annotation below the spring-boot-starter-web and then add the following dependency in pom.xml?
I know the last version also has a vulnerability, but I just wanted to know what should I do for this kind of situations (assume that the last version has no vulnerability)? Any idea?
<!-- https://mvnrepository.com/artifact/org.yaml/snakeyaml -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.33</version>
</dependency>
First off all don't panic and step back. Although the dependency mentioned has a vulnerability, if you don't actually use it (i.e. no YAML in your application) it actually doesn't apply. Those dependency scans are pretty dumb as they can only see dependencies not the fact that you are or aren't using them.
That being said, to fix you should upgrade the Spring Boot version for your application. For this, assuming you are using a Spring Boot as a parent, update that version.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.8</version>
</parent>
NOTE: Don't mix modules of different versions of Spring Boot (or any framework/library for that matter) as that will lead to problems. So don't put a version tag in your dependencies (at least not the spring-boot-starter-* ones!).
This has Snake YAML 1.30, if you can you could also upgrade to 3.0.2 which actually includes the 1.33 version.
To upgrade only Snake YAML you can just override the version property used by Spring Boot to manage the dependencies. The version properties are documented in the Spring Boot Documentation. How to override those versions is documented in the Spring Boot Plugin Documentation.
In short you would need to override the snakeyaml.version property with the version you wish to use (that is only for 2.7.x) if you upgrade to 3.02 you don't need this.
<properties>
<snakeyaml.version>1.33</snakeyaml.version>
</properties>
This will pull in that version. You don't need to exclude anything or use dependency management for this. Drawback when a new version of Snake YAML comes out and Spring Boot pulls that in, this will override it. So take care when updating after this.
This all being said, as mentioned in the beginning the fact that a certain jar/dependency is included doesn't mean it is a risk. If not used it won't pose a risk, so instead of panicking on Snyk warnings you should properly investigate them.
Try to update whatever brings you the dependency (here: spring-boot-starter-web)
If not possible: Add an entry to <dependencyManagement> with the newer version and put a comment into the pom.xml why you do this (Vulnerability XY).

Find all dependencies and their resolved versions in Gradle

I am looking for a way to display all the dependencies and their resolved versions in a Gradle project. I want the result to be flat.
Gradle has the dependencies task which prints the dependency tree, however, it is not flat and hard to read. For e.g. logback-classic has the following dependency tree.
| | | +--- ch.qos.logback:logback-classic:1.2.3
| | | | +--- ch.qos.logback:logback-core:1.2.3
| | | | \--- org.slf4j:slf4j-api:1.7.25 -> 1.7.30
Instead of this tree structure, I want the result to be following(dependencies with their resolved versions):
ch.qos.logback:logback-classic:1.2.3
ch.qos.logback:logback-core:1.2.3
org.slf4j:slf4j-api:1.7.30
This way it would be easy for me to find out the vulnerable libraries(for e.g. log4j), and it would also give me insights on dependent jars even if I don't directly use them.

Java | Multiple POM files in single project

I'm building an Automation Tool using Java Automation Framework under the hood, to which users will not have access to the main POM.xml file. Sometimes users require to add a custom Java function which requires additional depedencies / repositories. Presently I have to make changes to the main POM file to accommodate the user request. User has access only to "src/test/java/com/script/custom" folder to write custom scripts / functions. I have explored options like Parent/Child POM, Plugin Management, Profile, etc. but examples are mainly for multiple projects. I'm a NodeJs/Angular person, so I'm a beginner at Java.
Project
|
|--src/test/java/com/script/custom
| |
| custom_code.java
| |
| custom_pom.xml
|
--pom.xml
Users should only enter additional dependencies / repos in custom_pom.xml. Parent pom.xml will still hold the main dependencies/repos of the project.
Running code (apart from tests) is against the core concept of Maven as a build tool. There are ways, however, to excute arbitrary code at build time:
Exec Maven Plugin
without an additional plugin (and with cleanly separated projects):
+- project
| +- pom.xml
+- custom
+- src/main/java/com/script/custom
| +- CustomCode.java ... convention for Java class names is CamelCase
+- src/test/java/com/script/custom
| +- CustomCodeTest.java ... instantiates and runs CustomCode
+- pom.xml ... containing <parent><relativePath>../project
For <parent> see Introduction to the POM #Project Inheritance. See also Maven: Lifecycle vs. Phase vs. Plugin vs. Goal for further basics.

mvn validate throws Dependency convergence error but mvn dependency:tree does not show the dependency

mvn validate fails throwing dependency error.
Dependency convergence error for com.company.concepts:patients:2.4.14-SNAPSHOT paths to dependency are:
+-com.company.ion.concepts.patientlist:patient-list:1.4-SNAPSHOT
+-com.company.concepts:patientlists:2.3.15-SNAPSHOT
+-com.company.concepts:patients:2.4.14-SNAPSHOT
and
+-com.company.ion.concepts.patientlist:patient-list:1.4-SNAPSHOT
+-com.company.concepts:patientlists:2.3.15-SNAPSHOT
+-com.company.concepts:patients:2.4.14-SNAPSHOT
+-com.company.concepts:patients:2.4.4-Alpha-5
Then I have run mvn dependency:tree to see if anywhere I am using 2.4.4-Aplha-5 but did not find it anywhere.
[INFO] +- com.company.concepts:patientlists:jar:2.3.15-SNAPSHOT:compile
[INFO] | +- com.company.concepts:patients:jar:2.4.14-SNAPSHOT:compile
[INFO] | | +- com.company.xyz.common:xyz-common-demographic-proteus:jar:3.1:compile
I have tried every possible thing out there, but could not come to a solution.
I am using
maven-enforcer-plugin:1.4.1:enforce
Java version: 1.8.0_101, vendor: Oracle Corporation
Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5
Try with this instead. It should show the different paths to that dependency in your project:
mvn dependency:tree -Dverbose=true

Maven dependency Conflict - Trouble with understanding version managed from 2.6.0 [duplicate]

This question already has answers here:
How do I read a Maven dependency tree
(2 answers)
Closed 7 years ago.
I have a Maven dependency conflict.
It seems that I have jar conflicts and so I ran the following command -
mvn dependency:tree -Dverbose -Dincludes=com.x.b
Added the necessary exclusions and ran the command again to get the following output
[INFO] --- maven-dependency-plugin:2.2:tree (default-cli) # domain-crypto ---
[INFO] com.x.platform.y.z:domain-crypto:jar:119.1.0-SNAPSHOT
[INFO] \- com.x.b:java-cryptoclient:jar:2.6.0:compile
[INFO] com.x.platform.y.z:domain-processorclient:jar:119.1.0-SNAPSHOT
[INFO] \- com.x.platform.y.z:domain-crypto:jar:119.1.0-SNAPSHOT:compile
[INFO] \- com.x.b:java-cryptoclient:jar:1.1:compile (version managed from 2.6.0)
So from what I understand it should be 2.6.0 however what is causing me confusion is the "(version managed from 2.6.0)" part.
Does it mean that it is using 1.1 or does it mean its using 2.6.0?
during compilation of x.platform.y.z:domain-crypto, 2.6.0 will be present and your source will be compiled against that
during compilation of x.platform.y.z:domain-processorclient, 1.1 will be present and your source will be compiled against that
At runtime it depends on how you configured your app (usually whichever comes first in dependencies list gets precedence)

Categories