I have a project that exports a package for another project to import and utilize. Within Eclipse, it seems to resolve correctly. But when building with Maven, I get the following errors: The import x.x.x cannot be resolved. I've fiddled around with the manifest/ pom.xml and restarted Eclipse several times and the results are the same.
The general structure is:
com.my.company.plugin
- com.my.company.pkg
And within that manifest.mf, I have Export-Package: com.my.company.pkg
For the other plugin's manifest, I have Require-Bundle: com.my.company.pkg;resolution:=optional (I've tried taking the option portion out, but that didn't seem to matter)
And within the source for the second plugin, I have:
import com.my.company.pkg.MyClass
public class MyOtherClass implements MyClass {
Locally in Eclipse it all works fine. But when I try to build with Maven, I get the following error:
[ERROR] import com.my.company.pkg.MyClass;
[ERROR] ^^^^^^^^^^^^^^^^^^
[ERROR] The import com.my.company.pkg cannot be resolved
[ERROR] public class MyOtherClass implements MyClass {
[ERROR] ^^^^^^^
[ERROR] MyClass cannot be resolved to a type
The strange thing is that I have other imports within MyOtherClass that reference other plugins and added in the Required-Bundles. I'm guessing it's how I'm exporting the first plugin. What exactly am I missing?
---EDIT---
It seems like adding this block in the parent pom is causing it to fail. Which is odd because I thought it by setting it to ignore it will completely ignore the optional dependencies instead of trying to resolve it? While taking it out causes other areas that uses optional dependencies to fail...
<dependency-resolution>
<optionalDependencies>ignore</optionalDependencies>
<extraRequirements>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.ui</id>
<versionRange>0.0.0</versionRange>
</requirement>
<requirement>
<type>eclipse-plugin</type>
<id>org.eclipse.ui.views</id>
<versionRange>0.0.0</versionRange>
</requirement>
</extraRequirements>
</dependency-resolution>
Related
I'm having a really hard time with some Java modules. I'm working on an old Java project which has been "migrated" to Java 11. Nowhere in the project is there any module-info.java file defined.
I'm getting compilation errors in Eclipse/VS Code, which look like:
The package org.w3c.dom is accessible from more than one module: <unnamed>, java.xml
I don't fully understand why it's causing the problem, but I added a module-info.java definition to the root of the module.
module com.company.app {
requires java.xml;
}
And that compilation error went away. I now have visibility errors everywhere and many, many more than before.
I've started to fix the visibility errors with exports and imports entries as needed, but now I have a problem.
In one of the projects, there is a source and a separate source-test folder. I've defined a module definition in the source folder.
The code in the source-test folder is separate, but has the same package structure. The following code:
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.junit.experimental.categories.Category;
The import org cannot be resolved. (in the line of the import static).
The type org.junit.Test is not accessible (in the corresponding line)
The type org.junit.experimental.categories.Category is not accessible (once again, in the corresponding line.)
I don't want to add the junit dependency to the main project code, since it's a testing dependency. However, if I define another module-info.java module inside the source-test folder, it complains about the build path containing a duplicate entry 'module-info.java'.
How can the dependencies and modules be correctly defined?
Yesterday I faced an interesting issue after deploying my Java 8 webapp on Tomcat 8. Rather than how to solve this issue I'm more interested in understanding why that happens. But let's start from the beginning.
I have two classes defined as follows:
Foo.java
package package1;
abstract class Foo {
public String getFoo() {
return "foo";
}
}
Bar.java
package package1;
public class Bar extends Foo {
public String getBar() {
return "bar";
}
}
As you can see, they are in the same package and, ultimately, end up in the same jar, let's call it commons.jar. This jar is a dependency of my webapp (i.e. as been defined as dependency in my webapp's pom.xml).
In my webapp, there is a piece of code which does:
package package2;
public class Something {
...
Bar[] sortedBars = bars.stream()
.sorted(Comparator.comparing(Bar::getBar)
.thenComparing(Bar::getFoo))
.toArray(Bar[]::new);
...
}
and when it is executed I get:
java.lang.IllegalAccessError: tried to access class package1.Foo from class package2.Something
Playing around and experimenting I was able to avoid the error in three two ways:
changing the Foo class to be public instead of package-private;
changing the package of the Something class to be "package1" (i.e. literally the same as the Foo and Bar classes but physically different being the Something class defined in the webapp);
forcing the class-loading of Foo before executing the offending code:
try {
Class<?> fooClass = Class.forName("package1.Foo");
} catch (ClassNotFoundException e) { }
Can someone give me a clear, technical explanation that justifies the issue and the above results?
Update 1
When I tried the third solution I was actually using the commons.jar of the first one (the one where the Foo class is public instead of package private). My bad sorry.
Moreover, as pointed out in one of my comments, I tried to log the classloader of the Bar class and Something class, right before the offending code and the result for both was:
WebappClassLoader
context: my-web-app
delegate: false
----------> Parent Classloader:
java.net.URLClassLoader#681a9515
Update 2
Ok, I finally solved one of the mysteries!
In one of my comments I said that I wasn't able to replicate the problem by executing the offending code from a simple main created in a different package than Foo and Bar of the commons.jar. Well...Eclipse (4.5.2) and Maven (3.3.3) fooled me here!
With this simple pom:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>my.test</groupId>
<artifactId>commons</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>
if I execute "mvn clean package" (as Eclipse Run Configuration) and run the main from within Eclipse I get the wonderful IllegalAccessError (cool!);
if I execute Maven -> Update project... and run the main from within Eclipse I don't get any error (not cool!).
So I switched to the command-line and I confirmed the first option: the error consistently appears regardless by whether the offending code is in the webapp or in the jar. Nice!
Then, I was able to further simplify the Something class and discovered something interesting:
package package2;
import java.util.stream.Stream;
import package1.Bar;
public class Something {
public static void main(String[] args) {
System.out.println(new Bar().getFoo());
// "foo"
Stream.of(new Bar()).map(Bar::getFoo).forEach(System.out::println);
// IllegalAccessError
}
}
I'm about to be blasphemous here so bear with me: could it be that the Bar::getFoo method reference simply get "resolved" to the Foo::getFoo method reference and, since the Foo class is not visible in Something (being Foo package private), the IllegalAccessError is thrown?
I was able to reproduce the same issue compiling in Eclipse (Mars, 4.5.1) and from command line using Maven (Maven Compiler Plugin version 3.5.1, the latest at the moment).
Compiling and running the main from Eclipse > No Error
Compiling from console/Maven and running the main from Eclipse > Error
Compiling from console/Maven and running the main via exec:java from console > Error
Compiling from Eclipse and running the main via exec:java from console > No Error
Compiling from command line directly with javac (no Eclipse, no Maven, jdk-8u73) and running from command line directly with java > Error
foo
Exception in thread "main" java.lang.IllegalAccessError: tried to access class com.sample.package1.Foo from class com.sample.package2.Main
at com.sample.package2.Main.lambda$MR$main$getFoo$e8593739$1(Main.java:14)
at com.sample.package2.Main$$Lambda$1/2055281021.apply(Unknown Source)
at java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
at java.util.stream.Streams$StreamBuilderImpl.forEachRemaining(Unknown Source)
at java.util.stream.AbstractPipeline.copyInto(Unknown Source)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
at java.util.stream.AbstractPipeline.evaluate(Unknown Source)
at java.util.stream.ReferencePipeline.forEach(Unknown Source)
at com.sample.package2.Main.main(Main.java:14)
Note the stacktrace above, the first (pre-java-8) invocation works fine while the second (java-8 based) throws an exception.
After some investigation, I found relevant the following links:
JDK-8068152 bug report, describing a similar issue and, above all, mentioning the following concerning the Maven Compiler Plugin and Java:
This looks like a problem induced by the provided maven plugin. The provided maven plugin (in the "plugin" directory) adds "tools.jar" to the ClassLoader.getSystemClassLoader(), and this is triggering the problem. I don't really see much that could (or should) be done on the javac side, sorry.
In more details, ToolProvider.getSystemJavaCompiler() will look into ClassLoader.getSystemClassLoader() to find javac classes. If it does not find javac there, it tries to find tools.jar automatically, and creates an URLClassLoader for the tools.jar, loading the javac using this class loader. When compilation runs using this class loader, it loads the classes using this classloader. But then, when the plugins adds tools.jar to the ClassLoader.getSystemClassLoader(), the classes will begin to be loaded by the system classloader. And package-private access is denied when accessing a class from the same package but loaded by a different classloader, leading to the above error. This is made worse by maven caching the outcomes of ToolProvider.getSystemJavaCompiler(), thanks to which running the plugin in between two compilations still leads to the error.
(NOTE: bold is mine)
Maven Compiler Plugin - Using Non-Javac Compilers, describing how you can plug a different compiler to the Maven Compiler Plugin and use it.
So, simply switching from the configuration below:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
To the following:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerId>eclipse</compilerId>
</configuration>
<dependencies>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-eclipse</artifactId>
<version>2.7</version>
</dependency>
</dependencies>
</plugin>
Fixed the issue, no IllegalAccessError any more, for the same code. But doing so, we actually removed the diff between Maven and Eclipse in this context (making Maven using the Eclipse compiler), so it was kind of normal result.
So indeed, this leads to the following conclusions:
The Eclipse Java compiler is different than the Maven Java Compiler, nothing new in this case, but that's yet another confirmation
The Maven Java compiler in this case has an issue, while the Eclipse Java compiler has not. The Maven Compiler is coherent with the JDK compiler though. So it might actually be a bug on the JDK having effect on the Maven Compiler.
Making Maven using the same Eclipse compiler fixes the issue, or hides it.
For reference, I tried also the following without much success before switching to the eclipse compiler for Maven:
Changing Maven Compiler Plugin version, every version from 2.5 till 3.5.1
Trying with JDK-8u25, JDK-8u60, JDK-8u73
Making sure Eclipse and Maven Compiler were use exactly the same javac, explicitly using the executable option
To summarize, the JDK is coherent with Maven, and it is most probably a bug. Below some related bug reports I found:
JDK-8029707: IllegalAccessError using functional consumer calling inherited method. Fixed as Won't Fix (it was exactly the same issue)
JDK-8141122: IllegalAccessException using method reference to package-private class via pub. Open (again, exactly the same issue)
JDK-8143647: Javac compiles method reference that allows results in an IllegalAccessError. Fixed in Java 9 (similar issue, pre-java-8 code would work fine, java-8 style code would break)
JDK-8138667: java.lang.IllegalAccessError: tried to access method (for a protected method). Open (similar issue, compilation fine but than runtime error for illegal access on lambda code).
If packages commons.jar and jar with package2 are loaded by another class-loader, then it is different runtime packages and this fact preventing methods of Something class from access to package members of Foo. See chapter 5.4.4 of JVM spec and this awesome topic.
I think there is one more solution in addition to what you already tried: override method getFoo in Bar class
I created a new project on Play Framework 2.3.2 with Scala. I added two packages models and utils. Created a class in each package and made an import into the model from utils and I get this error :
[error] /media/hadareanrares/Media/Projects/TestingScala/app/models/Page.scala:3: not found: object utils
[error] import utils._
[error] ^
[error] one error found
Tried "_root_.utils._" and I'm getting the same result.
I seem to have fixed it by juggling with the class in the utils package.
I saw that IDEA IntelliJ detected the class in utils by importing as import _root_.ClassName, disregarding the utils package.
Then I moved ClassName to the root package, app. The compiler complained that it couldn't import _root_. so I moved the class back to the utils package and it seemed to have fixed it somehow after a rebuild.
The key thing that made it work was dragging the class from root to the utils package. It seemed to have updated links everywhere. But, have I not had the help of IDEA, how else would I fix this? I would like to use a simpler text tool, Sublime, that doesn't have the Scala integration that IDEA has.
You can try
activator reload // Reload the current application build file
and
activator update // Update application dependencies
then
activator idea // to recreate your IntelliJ files
I figured it out.. class in utils package didn't have "package utils" specified. Done.
I got a compilation error in my project on package which belongs to Junit (in org.junit, org.junit.experimental.results, org.junit.internal, org.junit.internal.matchers, org.junit.matchers, org.junit.rules).
all this classes are under junit package in my project, meaning: Security/src/org.junit, Security/src/org.junit.experimental.results, where Security is the name of my project. My classes that I wrote are under other package that I define: Security/src/myPackage/myClass
In all these classes, it gives a complation error in the import lines, for example:
import org.hamcrest.Description cannot be resolved
import org.hamcrest.Matcher cannot be resolved;
import static org.junit.matchers.JUnitMatchers.containsString cannot be resolved;
The checks are going OK (the green/red bar is display, and gives the correct result), but this problem give me an error on all the project.
Your JUnit version needs Hamcrest. You should include it in your buildpath or use an older JUnit version.
There are different JUnit packages of the release 4.10:
junit-4.10.jar: Includes Hamcrest, you should use this.
junit-dep-4.10.jar: Does NOT include Hamcrest, use this if you already have a hamcrest jar in your buildpath.
I successfully built the Scala-only project template from the sbt android plugin. Next, I tried to add some Java sources to my project and got the following error in TR.scala. TR.scala is a file generated from the Java sources.
[info] Compiling 2 Scala sources and 5 Java sources to D:\Workspaces\MyProject\my-project\target\scala-2.9.0-1\classes...
[error] D:\Workspaces\MyProject\my-project\target\src_managed\main\scala\com\mydomain\myproject\TR.scala:2: object app is not a member of package com.mydomain.myproject.android
[error] import android.app.Activity
[error] ^
[error] D:\Workspaces\MyProject\my-project\target\src_managed\main\scala\com\mydomain\myproject\TR.scala:3: object view is not a member of package com.mydomain.myproject.android
[error] import android.view.View
[error] ^
[error] two errors found
[error] {file:/D:/Workspaces/MyProject/my-project/}My Project/compile:compile: Compilation failed
[error] Total time: 5 s, completed Oct 12, 2011 11:20:55 AM
Thanks to Yifan Yu's response in Google Groups, it appears to be a bug in the sbt Android plugin. Thanks Jan Berkel, for fixing the bug in this release.
You have a package path named com.mydomain.myproject.android, so
it's confusing the compiler when it tries to compile TR.scala in
'com.mydomain.myproject', because it thinks of 'android.whatever' as a
relative path. The plugin tries to prepend _root_. to the Activity
source it generates, but it forgets to do so for TR.scala.
Well, you didn't say exactly what you did ("add some Java sources"? how's that? cut&pasted code? which code? where? what?), which makes it hard to give a good answer. However, the explanation is actually simple from the error message.
It gives an error when you do "import android.app.Activity". Might that be the Java sources you spoke of? Well, I don't know. But I know you have either imported or are inside the package com.mydomain.myproject.android, because it says so in the message. In other words, you have one of the following:
package com.mydomain.myproject.android
import com.mydomain.myproject._
import com.mydomain.myproject.android
before the other import. What that means is that the following two lines will be equivalent:
import android.app.Activity
import com.mydomain.myproject.android.app.Activity
Which is probably not what you want. You wanted android.app.Activity to be an absolute reference, right? Well, it is not. You can make it absolute like this:
import _root_.android.app.Activity
Or you can just not have a package named android in your project.