0

Trying to test my maven project (one parent pom and several modules (jpms modules)) I got annoying Error occurred in starting fork:

Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:3.0.0-M4:test (default-test) on project com.foo.plugin: There are test failures.
...
Error occurred in starting fork, check output in log
Process Exit Code: 1
org.apache.maven.surefire.booter.SurefireBooterForkException: The forked VM terminated without properly saying goodbye. VM crash or System.exit called?
...
Error occurred in starting fork, check output in log
Process Exit Code: 1
    at org.apache.maven.plugin.surefire.booterclient.ForkStarter.fork(ForkStarter.java:690)
    at org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:285)
    at org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:248)
    at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeProvider(AbstractSurefireMojo.java:1217)
    at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeAfterPreconditionsChecked(AbstractSurefireMojo.java:1063)
    at org.apache.maven.plugin.surefire.AbstractSurefireMojo.execute(AbstractSurefireMojo.java:889)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginM

A solution I found, for example, here suggested to set <forkCount>0</forkCount> in surefire-plugin configuration. However, such solution doesn't allow to run tests on module-path, so I went to this surefire issue.

Surefire developers (thanks to them) found out that the reason was in maven scope of the dependencies I used. In my project I have:

         <dependency>
            <groupId>jakarta.ws.rs</groupId>
            <artifactId>jakarta.ws.rs-api</artifactId>
            <version>2.1.6</version>
            <scope>provided</scope> <!-- NOTE IT -->
        </dependency>
        <dependency>
            <groupId>jakarta.xml.bind</groupId>
            <artifactId>jakarta.xml.bind-api</artifactId>
            <version>2.3.2</version>
            <scope>provided</scope> <!-- NOTE IT -->
        </dependency>

And they said it had to be:

          <dependency>
            <groupId>jakarta.ws.rs</groupId>
            <artifactId>jakarta.ws.rs-api</artifactId>
            <version>2.1.6</version>
            <scope>compile</scope> <!-- NOTE IT -->
        </dependency>
        <dependency>
            <groupId>jakarta.xml.bind</groupId>
            <artifactId>jakarta.xml.bind-api</artifactId>
            <version>2.3.2</version>
            <scope>compile</scope> <!-- NOTE IT -->
        </dependency>

And when I changed the scope my project was tested by surefire without problems. Both dependencies jakarta.ws.rs-api and jakarta.xml.bind-api are JPMS modules and are required by my JPMS modules.

So the question, is the problem in my code (provided is wrong if I want to run my tests for my JPMS module) or the problem is in surefire plugin?

Pavel_K
  • 10,748
  • 13
  • 73
  • 186

1 Answers1

1

NOTE: You can freely remove <scope>compile</scope> since no declaration of the scope in your POM means that the Maven will use the default value compile anyway.

The scope of provided is the project architecture aspect.

It is used in situations when the application server contains WS API (even if different arfifact file name). This way we mark it provided which makes the WAR file smaller and the WS API artifact would not be included.

In situations where you are also building serverless application and you are building your own container, then no scope of provided is needed to declare. There the artifact will appear within the Fat JAR which is what you expect.

So as you can see the dependency marked as provided copes with classpaths. It appears on Compiler classpath but it does not appear in runtime.

There is one more feature in the scope provided. It is the inheritance, where such of dependency cannot be inherited transitively. If you have such dependency witht the scope provided in a POM, then the inheritance would not see the dependency in a dependent child POM.

For more information pls see Maven documentation.

http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html

This scope is only available on the compilation and test classpath, and is not transitive.

tibor17
  • 1,043
  • 6
  • 9
  • I can't agree with you. I use `provided` as 1) I don't need fat JAR as fat jar is full contradiction to jpms, jpms modules, jpms layers. 2) I don't want my jpms war project include all other libraries, because, as it is also a jpms module it must use other jpms modules on module path. So, we have to be able to test any JPMS with `provided` scope and test it on module path. – Pavel_K Apr 24 '20 at 16:42
  • @Pavel_K I am not sure whether the JPMS is really used by anybody, especially in combination with Java EE or Jakarta EE. – J Fabian Meier Apr 24 '20 at 19:13
  • @JFMeier Now, now it is used. In our company we use Jetty in one JPMS layer, and web application in child JPMS layer. I asked Jetty developers and they added support of JPMS for Jetty and I saw that others thanked them. Now, as I know, they work on support of JPMS web applications. – Pavel_K Apr 24 '20 at 19:18
  • @JFMeier As I noted in my question jakarta.ws.rs-api and jakarta.xml.bind-api are JPMS modules, so they are moving to JPMS. And soon it will become very popular, as module systems give a lot of advantages. – Pavel_K Apr 24 '20 at 19:20
  • I doubt that the module system will be used by many people. You need to rewrite a lot of stuff in your applications and the benefits are unclear to me. – J Fabian Meier Apr 24 '20 at 19:23
  • @JFMeier No, I can't agree with you. 1) it will be used by many people - see how many people used OSGI and OSGI has never been a part of JDK 2) It is not necessary to rewrite a lot of stuff as for this purpose (in order not to rewrite a lof of stuff) automatic modules were invented. If you want you can find in internet - jpms automatic modules. – Pavel_K Apr 24 '20 at 19:26
  • And what do you gain from using moduels? – J Fabian Meier Apr 24 '20 at 19:29
  • @JFMeier This is a very wide topic and I can speak for hours. There are two types of advantages - software modularity advantages (see here http://gwentechembedded.com/the-advantages-of-modular-software-and-programming/# ) and JPMS advantages (see here https://dzone.com/articles/java-modularity-a-personal-journey) – Pavel_K Apr 24 '20 at 19:36
  • @Pavel_K I am a Maven developer in the Apache and I am guiding the developers in companies so I know what I am talking about. You can see that I had to fix your project in the Apache JIRA to make it working. The Maven modularity and Java modularity are two different things. Maven has its own rules and you have to obey these rules, does not matter it you use JPMS or not. You have to understand the transitive dependencies in a combination with scope _provided_ and this was my main message for you in the comment. Pls read it again and the documentation too. – tibor17 Apr 24 '20 at 19:51
  • @Pavel_K You can **repeat** the WS API dependency in the child POM (_com.goo.impl_). The scope is up to you. The test module path may be slightly different from normal runtime. That's the practical experience that you have to add some extra artifacts to the test module/class path, so you can use scope=test, it's uo to you. Your application server also has WS API on the module path but the test module path does not, so you have to add it since you suppressed transitive inheritance of WS API from _com.foo.api_ to _com.foo.impl_. – tibor17 Apr 24 '20 at 20:05
  • @tibor17 Ok. I am really very thankful to you for your explanation. I said at the beginning that I am very bad at maven. However, your first workaround - to change scope to `compile` can't be acceptable - see my first comment to your answer. Now I tried to use in com.foo.plugin scope=test for dependencies of com.foo.api. It works, but it is a very sad story... Could you say if there is another solution that allows not to include dependencies in target jar/war and not to add transitive dependencies with scope=test? – Pavel_K Apr 24 '20 at 20:27
  • The scope=test is not transitive. What I would do, I would add `jakarta.ws.rs-api` with `scope=test` in the module `com.foo.plugin`. The Maven does not control the **dependencies Resolver** via `module-info`. The Maven does not care except the compiler and surefire/failsafe, but the Maven has it's own rules and does not see JPMS rules. Basically, it is very ugly situation because there are two modularity principles, one fighting with another, and the developer is always the bad person because he has to understand both and maintain both independently and compatibility between these two worlds. – tibor17 Apr 24 '20 at 21:12
  • @tibor17 I asked you a question here https://issues.apache.org/jira/browse/SUREFIRE-1733 . Could you take a look? – Pavel_K Jun 04 '20 at 10:50