How do you guys work with multi-module dev efforts?
I don't use Maven or Gradle or other technologies, just IJ. I have multiple (Java 9 )modules . I want them all open at once so they all appear in the project view. They're effectively libraries that call each other which I am also modifying at will. How do you guys do this? I had one module that I added all the others to. So a holding module as it were. Then i changed that to a single project that I added (Java 9) modules to . Thing is, when I did it the second way all my Service and Service Providers stopped being able to find each other when I run a PSVM from one of them. I am not sure why. All my Java 9 Modules Ts are crossed and all Is are dotted. It *ought* to work but they can't find each other. The difference between the working version and non working version of the code base is not one byte but but but the way I structured the two projects is different as I described. Other than the structure, no a single difference exists between any file of these two projects.
I am doing something wrong but I don't know what it is.
Please sign in to leave a comment.
Could you provide screenshots of your Project View and Modules settings? (File | Project Structure | Modules)
Do you have module-info.java configured?
Also, please share the error output you see after starting the PSVM.
> I don't use Maven or Gradle or other technologies, just IJ
I strongly recommend you to use one of this. Thats handy and huge time economies, trust me and make your project more flexible & independant.
Egor,
Hey thanks for replying. Yes I have module-info.java for every Java module involved in both cases. In the working project, I can cause Java 9 Module errors if I forget an "export" or "provides with" or "uses" statement in any of the module-info-java files.
Today I will isolate the issue down to just a couple classes, both in two projects: one working and the other non-working and post a the screenshots you requested.
The fact I am having this problem strongly suggests my long-standing understanding of how IJ modules intersect with and effect Java 9 Modules is defective somehow. Something about how I've structured one of these IJ projects is undermining my use of ServiceLoader.lookup( class ) in a way I would have said can't happen. I know it's some fundamental error in my use of IJ wrt to Java 9 modules but I just can't figure it out.
nikitasius,
Yeah everyone uses these things and people find them to be as you say. It just so happens that I haven't yet been forced to work with them and that's (technical) time I'm better off spending in ways which expand my technical frontiers. For example, I never learned Git until I realized that clearing IJ's caches was just always going to wipe out IJ Local History. In this sense, I routinely avoid as many technologies as I can.
i had same situation maaaany years ago. But git + gradle (in kts syntax) is musthave these days for commercial development.
Egor,
OK I was able to piece together what's happening. The issue boils down to this- it's not clear what the cause and effect relationship is between 1) the drop down, radio button and fill-in choices made in a) the Run/Debug-->Configuration dialog and b) the Project Structure-->Modules-->Dependencies dialogues and 2) the value of java -p, that is, the value of module-path, the application ends up running with.
To get at this, I created a Project, call it myProject. It has multiple modules. One of the modules utilizes ServiceLoader() to locate a service, (since that is the code which was failing).
The project, myProject, had three (Java-9-style) modules- a service module, an implementation module and a consumer module which did the obvious things their names suggest.
consumer had a PSVM which used the ServiceLoader to load a service implementation. That service implementation was defined in service and implemented in implementation.
The PSVM in consumer just output a message via System.out.println() to prove it had been handed the service implementation defined in implementation by the ServiceLoader. That's all these classes in myProject did.
I wrote all the module-info.java files correctly including the "uses" and "provides" statements. I could prove the code was good because I could manually go to the command line and get the program to run, inputting the correct value of the module-path variable to the java command .
However, when running it through IJ, while it did run, the ServiceLoader never found the implementation.
The reason for this is if you run the application, the automatically assigned value of -cp in the Run/Debug-->Configuration dialog will just be whatever dependencies are on the dependency list for the module which has the PSVM you're running, in this case consumer . But that is wrong. The dependencies of module consumer cannot be assumed to be the value of module-path- the implementation module has to be a member of the module-path also, but the implementation module is expressly NOT on the dependency list of the module consumer since I used a ServiceLoader to avoid exactly that.
So the value of classpath consumer or service or implementation. It has to be myProject. IJ will always default to consumer, or the module which contains the class being run, and if that module uses ServiceLoader, then that default will always be wrong.
Here is the full command IJ automatically produced with any output (there is none) . The entries of the module-path are on their own lines for clarity:
/mnt/Green/sdkman/candidates/java/18-open/bin/java -javaagent:/mnt/Green/jetbrains/idea-IU-221.5787.30/lib/idea_rt.jar=44797:/mnt/Green/jetbrains/idea-IU-221.5787.30/bin -Dfile.encoding=UTF-8 -p
/mnt/Orange/javaDynamic/moduleProofs/out/production/consumer:
/mnt/Orange/javaDynamic/moduleProofs/out/production/service
-m consumer/consumer.ServiceConsumer
Here is the run command which I produced at the terminal which made the program run correctly, with correct output:
~$ java -p
/mnt/Green/fakeIjProject/moduleMystery/out/production/consumer:
/mnt/Green/fakeIjProject/moduleMystery/out/production/implementation:
/mnt/Green/fakeIjProject/moduleMystery/out/production/service
-m consumer/consumer.ServiceConsumer
next = implementation.ConcreteImplementation@72ea2f77
hello.
Notice implementation is on my module-path but not IJ's
The solution is to 1) add all the modules as dependencies to the "project" in the Project Structure-->Modules-->Dependencies dialogues and then 2) select the project myProject in the drop-down as "-cp" (classpath) in the Run/Debug-->Configuration dialog.
Here's the issues with that as I see them.
1) Since Java 9, the default assumption which the run dialog embodies -that the PSVM's module's dependencies for compilation will be synonymous with the module-path's entries- is faulty. The Run behavior defaulted to by IJ over a set of perfectly formed classes will fail. That shouldn't be the case. The default should either be right or if that's not possible, it should help the programmer make it right, which is 2 below.
2) the need to define a non-code, non-Java, IJ-only entity: myProject, in order to produce a correct module-path at the java command is counter-intuitive, meaning, it's not something anyone would think of since IJ projects are a IJ thing and the command-line and its module-path and java command only deal with Java things. So essentially I have to have this IDE-only entity, myModule defined in a certain way and be a participant in the module path to get IJ to spit out the correct module-path.
It wouldn't be that bad except there is zero mention of the effects any of these dialogues have on the module-path. The words "module-path" never appear in any of them and the Project Structure-->Modules-->Dependencies serves a dual purpose of defining the compile time dependencies for module consumer but not the correct module path which is the same Project Structure-->Modules-->Dependencies dialog if I am dealing with myProject.
So in other words, instead of having the programmer consciously define and see the module-path a program will run with, the module-path is cobbled together by choices the programmer makes in various dialogues some of which- assigning modules to the project as dependencies- are not defined in Java, not a part of Java and have no clear relation to the complete module-path, meaning the dependencies assigned in consumer are not enough to have a class in consumer run.
What I would like to see is the module-path elevated to a first class entity of contemplation and construction. That is, the programmer can construct it through dialogues whose connection to and effect upon the module-path value is made clear at the time. Then I would like another dialogue available which shows me the module-path the program will be run with.
As it is now, none of that is really very clear and worse, the whole program will compile fine but then the defaulted-to, IJ-created Run "configuration" will fail the program in non-obvious ways. In a huge code base where there's lots of real Java things might be wrong and thus lots of places to look for errors, discovering this is what the problem was was just no fun !
Thank you for your clarifications. IntelliJ IDEA constructs the classpath for the application based on the project configuration. If it only has Java 9 modules which are correctly configured, there must be no issues with module-path. Btw there is a small clarification in the documentation on differences between java 9 modules and IDE modules.
From only the description though it is hard to understand what issue could be. It could either be an IDE bug or a project misconfiguration. Do you have all the modules set up as Java 9 modules in project?
In case there is indeed a bug, I would advise to check the 2022.2 IDE version (the EAP is already available at https://confluence.jetbrains.com/display/IDEADEV/IDEA+2022.2+latest+builds) It can be installed and run together with 2022.1.X versions. It has related issues, including the IDEA-183692 Maven project with a mix of Java 9 modules and Java 8 automatic modules fixed.
If there is still an issue, can you provide a sample project to investigate? For uploading you can use https://uploads.jetbrains.com All data is used by developers only for internal investigation needs.
P.S. I would also advise to use Maven or Gradle for structuring JVM-based project. It is established standard everywhere and also it allows you not to depend on IDE-specific configuration. When you load such a project into IntelliJ IDEA, it will automatically configure and set up the project structure. It is also convenient to share such projects between build environments - would only need to share (e.g. in VCS) Maven/Gradle configuration for this.
OK thank you.
I'll just leave the post here so other people can happen upon it.
> IntelliJ IDEA constructs the classpath for the application based on the project configuration. If it only has Java 9 modules which are correctly configured, there must be no issues with module-path.
I get what you're saying. If I config the project correctly, Jetbrains wants to know if things are still wrong and for me to file a bug report. I would do that but it's not the issue exactly.
The issue is the way the module-path variable obtains it value is opaque. It requires an entity which has no definition in the Java language and has no meaning to the java command itself ( java -p blah blah -m, blah blah), the IJ project itself, have 1) dependencies assigned to it and 2) be the value of "-cp" (even though it's technically not the classpath, it's the module-path) .
I should be able to consciously construct the module-path, by name, and not have its value be a side effect of assigning "dependencies" to an entity which Java knows nothing about, specifically the entity named "an IJ project". There should be a 1:1 correlation between the variables on the command line, including the module-path value, and some configuration values in the GUI so that I can consciously control the values of those variables on the command line when the app runs . Said again, I should be able to, using the IJ GUI, see the value of module-path, so named, and assign a value to it. As it is I have to select an imaginary (to java) entity (an IJ project) in the dialogues I mentioned and "configure" it. Only then will the module-path will be "configured correctly".
The reason I am saying all that here instead of a RFI elsewhere is because realizing the GUI is less than clear wrt to module-path construction turns out to be the resolution to the problem I had originally. So for the sake of anyone with the same or similar problem who may happen upon this page, I'll leave the explanation of what's going on here.
Thank you for your time. IJ is a truly awesome achievement and the support offered on these pages and elsewhere should be considered the standard for of customer support for all products.