In Eclipse, what is the difference between modulepath and classpath, and which one should I use to add a JAR file in the lib folder?
And why does the JRE System Library appear in modulepath?
The module system has mainly the following impact on the code:
A package can only be accessed from one module (Nested packages are treated as separate, so even though the package java.util is in the module java.base, the package java.util.logging can be in the module java.logging)
You can only access public fields and methods of code in exported packages of other modules. This is true even with reflection (i.e. java.lang.reflect.AccessibleObject.setAccessible(boolean) only works for code in the same module)
All code that is on the classpath lives together in the "unnamed" module.
All code on the modulepath lives in their own "named" modules.
You have to distinguish two cases:
If you don't add a module-info.java to your project, your project will be part of the unnamed module and can see all other code in the unnamed module, plus code in java.base and code in modules in java.se root module. Basically this means that w.r.t. code on the classpath, everything still works as in Java 8, so you should just put your dependencies on the classpath.
If you have a module-info.java in your project, your project will be in its own named module and can only see code in java.base and other named modules which are references using "requires"-clauses in the module-info.java. As named modules are only found via the module path, you should put your dependencies on the module path. This even works for jars created before Java 9, which will get a module name derived from the .jar file name (in which case they are called "automatic" module).
The JRE is always on the module-path, so that its internal code cannot be accessed even from code on the classpath.
There is one special case: If you have a module-info.java in your project and have test code in your project, you usually don't want to mention test dependencies like junit in the module-info.java. There are two solutions for this:
Create a dedicated test module. This has always been the convention for osgi-based projects. Disadvantage is that you can only use public API in your tests
The solution used by Maven: Put your test dependencies on the classpath. When compiling test code, Maven adds command line options that allow the code in the named module to read the unnamed module (which is not possible via the module-info.java).
In Eclipse Oxygen, the Maven solution was not possible, because it has no notion which code is test code, but this has been implemented in the upcoming Eclipse Photon (4.8) release, which will be out in June. You can already work with the (feature-complete) milestone builds from http://download.eclipse.org/eclipse/downloads/. In case you find any bugs, please report them at https://bugs.eclipse.org/bugs/.
Related
I have an application that has both JPMS modules and old fashioned non modular jar files. I don't want to put all of the jars on the classpath because then I loose some specific functionality baked into the modules (such as JPMS service provider interface). I also can't put the old fashioned jars on the module path as automatic modules because they have many package name conflicts.
The solution is to use both the module path and classpath at once. I could define the contents of my classpath and module path manually but this is liable to breaking if a dependency changes with a new version. As such this really needs to be done automatically and I have seen that this is actually done with maven-surefire when running unit tests as well as eclipse when launching the application from the IDE.
Does anyone know if there is a an existing library (or preferably maven plugin) that allows me to separate the dependencies that can be on the module path and the dependencies that have to be on the classpath in the same way that surefire or eclipse does?
I have used SBT to build a pure-java project. This project consists of multiple modules, and projectB depends on projectA.
Now after switching to JDK 11, this dependency should be modeled not via classpath but via module path.
Is it possible to tell SBT that module depencencies must be resolved via module path instead of the classpath?
Basically I have set up a inter-(sbt-)module depencencs that says projB.dependsOn(projA) - so can I tell SBT somehow to put this depencency on the javac module-path instead of using the classpath? I see currently no way of doing that.
EDIT: Further analysis showed that I needed also to use normal library depencencies (from libraries on a nexus repository) as module depencencies. So the next question would be - how can I treat these library depencencies as module depencencies in SBT?
I do know that SBT is a scala build tool, and that it is something of a stretch to use it for a java-only project, but I use SBT for other (scala-)projects, and I do not want to introduce too many different build tools, until I really have to. So - is there a sbt-level solution for this?
EDIT: To clarify the issue - the project in question is a kind of open-source library which we modified. The SBT build file is from our organization, so I have to maintain it.
The project switched to using module-info classes, and it depends on other (binary-only) libraries via module path, if you include module-info.java in the compilation, that is.
So in our SBT build I have to use the module path for some of the external library depencencies.
Also the SBT-subprojects have dependencies on each other, i.e. we also have to use the module path for that.
Is there a way to tell SBT that:
This library must be on the module path, and not on the classpath
This project dependency must be on the module path, and not via classpath?
That is the core of the question. I may be able to write a plugin for the first problem (having not libraryDepencencies, but modularLibraryDepencencies for example) - but I do not yet know how I could handle the second part (tell a project that project depencencies must be on the module path and not on the class path).
What is the difference between the maven scope compile and provided when artifact is built as a JAR? If it was WAR, I'd understand - the artifact would be included or not in WEB-INF/lib. But in case of a JAR it doesn't matter - dependencies aren't included. They have to be on classpath when their scope is compile or provided. I know that provided dependencies aren't transitive - but is it only one difference?
From the Maven Doc:
compile
This is the default scope, used if none is specified. Compile
dependencies are available in all classpaths of a project.
Furthermore, those dependencies are propagated to dependent projects.
provided
This is much like compile, but indicates you expect the JDK or a
container to provide the dependency at runtime. For example, when
building a web application for the Java Enterprise Edition, you would
set the dependency on the Servlet API and related Java EE APIs to
scope provided because the web container provides those classes. This
scope is only available on the compilation and test classpath, and is
not transitive.
Recap:
dependencies are not transitive (as you mentioned)
provided scope is only available on the compilation and test classpath, whereas compile scope is available in all classpaths.
provided dependencies are not packaged
Compile means that you need the JAR for compiling and running the app. For a web application, as an example, the JAR will be placed in the WEB-INF/lib directory.
Provided means that you need the JAR for compiling, but at run time there is already a JAR provided by the environment so you don't need it packaged with your app. For a web app, this means that the JAR file will not be placed into the WEB-INF/lib directory.
For a web app, if the app server already provides the JAR (or its functionality), then use "provided" otherwise use "compile".
Here is the reference.
If you're planning to generate a single JAR file with all of its dependencies (the typical xxxx-all.jar), then provided scope matters, because the classes inside this scope won't be package in the resulting JAR.
See maven-assembly-plugin for more information
compile
Make available into class path, don't add this dependency into final jar if it is normal jar; but add this jar into jar if final jar is a single jar (for example, executable jar)
provided
Dependency will be available at run time environment so don't add this dependency in any case; even not in single jar (i.e. executable jar etc)
For a jar file, the difference is in the classpath listed in the MANIFEST.MF file included in the jar if addClassPath is set to true in the maven-jar-plugin configuration. 'compile' dependencies will appear in the manifest, 'provided' dependencies won't.
One of my pet peeves is that these two words should have the same tense. Either compiled and provided, or compile and provide.
If jar file is like executable spring boot jar file then scope of all dependencies must be compile to include all jar files.
But if jar file used in other packages or applications then it does not need to include all dependencies in jar file because these packages or applications can provide other dependencies themselves.
I have a weird requirement where source is being generated by a jar based on the source in src/main/java. The final jar should bundle the files that are generated not the files that are in src/main/java.
Here's what I have done:
1. Added source in src/main/java
2. added maven-exec-plugin to invoke main-class from the jar added as dependency and passed required arguments.
3. added build-helper-maven-plugin to add the path to the generated sources to the maven sources.
4. added maven-jar-plugin to include and exclude the required classes.
Problem: When step#2 is executed the main class complains that its not able to find the class which is present in src/main/java. Is it a requirement to compile the class before it is used to dynamically create an instance...like Class.forname("package.Class")?
If maven-exec-plugin is execute after "compile" phase then there's no ClassNotFoundException but the problem with this is the generated source files do not get compiled before being bundled and I see files with ".java" extension being bundled in the generated jar.
Make your life simpler: use maven modules
root
|
+----> generator
|
+----> generated
Split your project into two modules, a generator module and a module with your generated code. That way, in each modules, you can embrace the standard maven lifecycle:
In the generator module, everything is completely normal.
The "generated" module referenced the "generator" module as a dependency with scope provided, and it executes the exec plugin in phase generate-sources, using the folder target/generated-sources/<your generator> as output folder. You probably need the buildhelper-maven-plugin to add the generated sources folder as source root also. Everything else works completely as usual.
I'm using IBM Integration Designer 7.5, which is a version of Eclipse 3.6 with some added features. I'm building a dynamic web project targeting Tomcat. The web project has a dependency on another project, a utility module.
I've configured the web project to include code from the utility module per this question and it works well. A WAR built from the web project includes a jar containing the class files from the utility module.
The problem is that the utility module includes some junit testcase classes, and they're being included in the jar that goes into the WAR. I'm looking for a way to leave out the junit classes.
In the utility module, the "real" code is in a folder called "src" and the test cases are in a second source folder called "test". I've gone to the Build path->Order and Export tab of the utility project, and it lists both "src" and "test" as exports. It's not possible to uncheck the box for the "test" entry. The eclipse documentation says that source folder are always exported from a project.
Is there a realistic way to fine-tune this setup so that the test cases aren't packaged into the web project?
Do you have the source for the utility modue? What are you using as a build tool? If the answer to the first question is yes and the answer to the second question is not Maven, then use Maven. By default it excludes anything in the src/test directory from the build artifact. You will need to either rearrange your project directories to be the Maven default, or do some configuration of your POM file so that Maven knows which is the test directory.