Very simple use case, I am using Eclipse Oxygen 4.7.3a that includes support from Java 9. I have two projects that are Java 9 projects:
- projectOne
| - src
| - module-info.java
| - com
| - package1
| - first
| Classificator.java
- projectTwo
| - src
| - module-info.java
| - com
| - package2
| - second
| Classifiable.java
I want to use the Classifiable class inside the Classificator, so I try to import the second module into the first project.
module-info.java Project 1:
module projectOne {
requires projectTwo;
}
module-info.java Project 2:
module projectTwo {
}
Eclipse is giving me the error:
projectTwo cannot be resolved to a module
Do I have to gather all my Java projects under one "main project" in order to let Eclipse know that all those modules are usable inside it? Or have I missed something else?
No, you don't need them to be in the same directory. Ideally, your project-one module defines some uses, which are implements by your project-two module (or vice-versa). Get the runtime implementation of your used interfaces. For this, both jars/classes must be on the module path.
For further information on module build, multi module builds,... you can refer to this link. Even if you do not use gradle, its tutorial on java 9 module build is quite interesting and gives some insight.
While wiring as a service is certainly a viable approach (as described in the other answer), let me add that requires can be made to work, too, of course.
The thing that was probably missing from the first approach is: Eclipse still needs to know where to look for modules. In real world projects this will typically be mediated by your build tool of choice plus a plug-in like m2e or buildship.
If no such plug-in is used, a normal project dependency should be added to the Build Path of project projectOne in order to make project projectTwo visible. Once the project is on the Build Path the module defined by the project can be resolved in references in module-info.java.
Related
I have a problem moving packages in IntelliJ IDEA. I have created Maven project with multiple modules and each of those modules has a package with the same name. Now whole project becomes a mess if I try to rename some of the packages.
My current project structure is something like this:
--parent-module
|
|--module-one
| |--src
| |--main
| |--java
| |--somepackage
| |--someotherpackages
|--module-two
| |--src
| |--main
| |--java
| |--somepackage
| |--somemorepackages
|--module-three
|--src
|--main
|--java
|--somepackage
|--someevenmorepackages
Notice that somepackage is present in all maven modules.
After MANY created classes in all of those modules and packages I have finally realised what have I done. Now I need to put somepackage into another package under java so I can have something like com.example.moduleone.somepackage.
I have tried renaming package but it renames it in all modules and that creates hailstorm of errors in the code. Also, IntelliJ IDEA renames it to com.example.moduleone.somepackage in all of the modules.
Any help would be highly appreciated.
Might be easiest to create the new package first and then move the classes you want to move into it and then delete somepackage once everything have been moved around
So first add moduleone, then move all of the classes you want to move, then do the same for the other modules, then delete somepackage
Right click to Project name > New> Module..> chose java version and set name for new module.
Drag your packpage your want move to new-module/src > OK > Refactor.
Rebuild project. Find erro : java: packpage dose not exist. Fix it by: Go to erro code > Atl+Enter > Add depedency on module..
I have a project(Java 12) with several Maven dependencies, and now I'm trying to add module-info file like
module mymodule {
requires java.net.http;
}
But if I do this all Maven dependecies (in pom.xml) become invisible for code, and compiler throws errors like java: package org.openqa.selenium.safari is not visible
(package org.openqa.selenium.safari is declared in module selenium.safari.driver, but module mymodule does not read it)
Is it possible to make them work together?
The new module info ist not congruent with the information in the pom.xml. Robert wrote a good article about the differences of both systems:
https://www.sitepoint.com/maven-cannot-generate-module-declaration/
I have two Java projects, built with ANT, named Project A and B which I created in Luna Eclipse (the Java EE version). The package structure is as follows:
Project A
|
src
|
SomePackage
|
A.java
Project B
|
src
|
AnotherPackage
| |
| B.java
|
SomeOtherPackageInSrc
|
C.java
where A, B, and C are non-abstract POJOs. I also have the following inheritence structure:
C extends B, B extends A.
I added a public method to A, so that its children could have it. I then built project A, and added the resulting JAR to the project B's Build Path. I noticed that C could not access the new method. I then attached the source JAR to the build path, viewed the the source for A.java, and the newly added method was present. I tried a number of things, and adding project A to the Deployment Assembly of project B allowed C to see the new method from A. Why does simply extending the class and adding the jar in which the extended class lives not provide visibility to public methods in this case?
I suppose, only extending and adding the project to your classpath will make it compile, but it is not automatically in the resulting deployment unit (EAR/WAR). ANd this makes the classes unavailable at runtime.
I found the problem. I had multiple versions of the Project A JAR on my classpath, and the compiler picked up the old JAR instead of the new one. Rookie mistake.
I have written (with Eclipse) a small program which uses JPA. Now I want to manualy compile and run this program using command line. I have also placed all source files in a separate directory (not within Eclipse's work space). The directory looks like:
directory
|- src
| |- javax
| | |- persistence
| | |- <...>
| |- main
| |- META-INF
| | |- javax
| | | |- persistence
| | |- persistence.xml
| |
| |- <..>
|- run.bat
Note: I purposely have 2 javax directories with all the class files in them.
run.bat contains lines:
javac -cp ./src ./src/main/Main.java
java -cp ./src main.Main
As far as I understand I am getting errors not because of the issue with the META-INF/persistence.xml file (not like many other people on stackoverflow). I am saying so because I have writen following lines in my Main:
<...>
Thread.currentThread().setContextClassLoader(new ClassLoader() {
#Override
public Enumeration<URL> getResources(String name) throws IOException {
System.out.println("resource requested=" + name);
if (name.equals("META-INF/services/javax.persistence.spi.PersistenceProvider")) {
<--- MARK ---> return Collections.enumeration(Arrays.asList(new File("src/javax/persistence/spi/PersistenceProvider.class")
.toURI().toURL()));
} else if (name.equals("META-INF/persistence.xml")) {
return Collections.enumeration(Arrays.asList(new File("src/META-INF/persistence.xml")
.toURI().toURL()));
}
return super.getResources(name);
}
});
emFactory = Persistence.createEntityManagerFactory("uzduotis");
<...>
So when I launch run.bat the program prints:
resource name=name=META-INF/services/javax.persistence.spi.PersistenceProvider
(it never gets to the part where program asks for "META-INF/persistence.xml" resource)
then it breaks and gives me an error:
If I change MARKED statement to
return super.getResources("src/" + name);
then the error says only:
What am I missing?
Peristence.xml:
EDIT:
Program prety simple: no hibernate, just a few classes which retrieve some info from REST service and work with it, mainly using javax and w3c external libraries. Photo of the project explorer to depict its simplicity.
EDIT 2. SOLUTION
I found a way to make it work although I am not entirely sure about the causes. So if anyone could answer why the following changes solved the issue I would gladly mark it as an answer
I added eclipselink and mysql-connector-java jars to the src directory. eclipselink.jar fixed the issue and mysql-connector-java.jar was needed because I got other error (I am working with database afterall). Finally I changed line in the run.bat file from
java -cp ./src main.Main
to
java -cp ./src;./src/eclipselink.jar;./src/mysql-connector-java.jar; main.Main
It seems that your application is a standard Java SE application. JPA does not work automatically, as standard Java SE environment does not contain any implementation of JPA interfaces. It seems that Eclipse adds eclipselink to the classpath under the cover, therefore your program works when you run it from within Eclipse. But when you run your program from command line, you need to add eclipselink, which is a library that contains functionality for JPA interfaces.
You may try to generate Ant build file from eclipse project, and you would see if it adds eclipselink into the classpath in build.xml file. Or even better, I recommend to turn your project into project with Maven build - you would be able to build and run your project using Maven command in the same way as Eclipse would execute it (as Eclipse uses Maven under the cover for Maven-based projects).
Edit - explanation of the role of eclipselink in JPA
Packages starting javax.persistence are mostly interfaces, annotations, they have very few classes in fact. They only define how your application communicates with underlying persistence mechanism in standard way. On the other hand, you need to include also library with implementations (classes) for the standard JPA interfaces. javax.persistence.Persistence is just a facade, which delegates all the hard work onto an implementation, which might be Eclipselink, Hibernate, or something else.
The relationship between javax.persistence and EclipseLink is similar to relationship between interfaces and classes. You may use interfaces in your code, but your application will work only if you supply interfaces with real classes at some point.
It is also possible to use Eclipselink directly and skip whole javax.persistence layer, similarly as it is possible to work with real classes directly without through interfaces. But then you need learn internal API of Eclipselink and it is not possible to change Eclipselink library for alternatives like Hibernate. Nor will you be able to reuse the knowledge of Eclipselink-specific API to a project, which uses Hibernate. Reusability of a standard API is the most important case for standardized javax.persistence interfaces.
Maybe you wonder, how the persistence API knows where it should delegate the required functionality. There are multiple hooks, how it can find out. It is possible to include path to the main implementation class in persistence.xml using provider element. Or, it simply works if you include Eclipselink into the classpath, as Eclipselink library contains special text file at standardized path, which contains required information. This special file is inside Eclipselink JAR at path META-INF/services/javax.persistence.spi.PersistenceProvider - does it ring the bell?
I'm working on a plugin for a 3rd party software that is quite undocumented. For the plugin I'm using a external lib (.jar) managed by maven and is later on executed on a tomcat server. Everything was working great till I updated to the latest release of the library, which now is using java.util.serviceLoader in order to load a concrete implementation of a interface. When build, my project has this package structure on a tomcat server:
mypluginPackage.jar
|
---META-INF
---lib
|
--- theExternalLibUsingServiceLoader.jar
|
---META-INF
|
---services
|
--- full.path.to.TheFactoryInterface
---external.lib.path
|
--- TheFactoryInterface.class
--- TheConreteClass.class
--- mypluginCore.jar
|
---META-INF
--- my.plugin.path
|
--- MyClassUsingTheExternalLib.class
As you can see, the external library has the correct services entry which is necessary for the serviceLoader to find the concrete of a interface within META-INF. The content of the full.path.to.TheFactoryInterface file is full.path.to.TheConcreteClass, which seems legit.
My plugin (package as well as the core) however do not have any of those META-INF information.
What happens now is that every time my plugin is using a method that will trigger the serviceLoader of the external library, the serviceLoader is unable to find the concrete implementation.
What I already tried is adding the exact same services/full.path.to.TheFactoryInterface to all my META-INF directories, which is not working (I guess I would need to change the content of the full.path.to.TheFactoryInterface file but I'm not sure - because of the undocumented plugin structure for the 3rd party software - what the right (relative) path would look like).
Can anybody give me a shot what I'm doing wrong here and how to fix it so the concrete class is found by serviceLoader? What META-INF folder should the services folder with it's content be placed in and should I change the paths? Is that the error at all or am I missing something compleatly different?
I understand that this is a very special topic since the 3rd party software is unkown, but any information depending serviceLoader and it's behaviour when run across multiple jars with multiple META-INF folders and in different execution context / classpaths would be appreciated.
I was able to get it working by extending the external lib so I'm able to provide a custom ClassLoader. Turned out, the default ClassLoader was wrong.
Also I was able to get in touch with the 3rd party tool devs and get the information I needed - call it "social decompiling".
Everything working now.