Java 11 with Powermock - Are they compatible? - java

After switching to Java 11, all the powermock related tests (annotated with #RunWith(PowermockRunner.class) and #PowerMockIgnore) are failing.
Is this known issue? I read a relevant SO post which was posted a year ago, and the latest release of Powermock was 2 months ago. I don't see any difference in behaviour with JDK 11.

For better clarity, it would be great if you could specify the powermock API version, what i can think of the probable clause of the exception would be PowerMock classloader reloads XML11Configuration but without specifying module/or ignore module of the class. As result the unnamed module is autogenerated.
I can suggest another workaround. If it works then my guess is correct. Could you try to
use this option #PowerMockIgnore({"com.sun.org.apache.xerces.", "javax.xml.parsers.",, "javax.xml.", "org.xml."})
It should work.

The existing "mvn hpi:run" command will not work correctly on Java
11 unless Java modules are downloaded and passed to the environment.
List item If you use Mockito/PowerMock in your plugin tests, you may need to update to the recent versions with Java 11 support-
You may also need to add test annotations to workaround PowerMock
Issue #864. Example for the Jenkins Core

Adding byte buddy dependency helped me to run PowerMock tests in java 14.

As mentioned above PowerMock reflection access internal packages java.xml/jdk.xml, a workaround consist in allowing access to those internal packages :
if you are using maven to build your project you should add the JVM argument :
--add-opens java.xml/jdk.xml.internal=ALL-UNNAMED
for example :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>--add-opens java.xml/jdk.xml.internal=ALL-UNNAMED</argLine>
</configuration>
</plugin>

If use reflect in JDK11, you might see some warning like 'An illegal reflective access operation has occurred', because reflect JDK inner API is illegal since JDK9, still you can use it with a warning above.
To fix the problem temporary, try to use --add-exports or --add-opens in your argLing.
For example: --add-opens java.xml/jdk.xml.internal=ALL-UNNAMED
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<argLine>
#{argLine} --add-opens java.xml/jdk.xml.internal=ALL-UNNAMED
</argLine>
</configuration>
</plugin>
For more infomation, watch --add-opens introduce

Related

Error when running the Spring Boot testing codes in a JMPS modular application

I am trying to create a modular Spring Boot sample using JMPS which introduced in Java 9.
Currently, I created a standalone Maven module for the testing work.
module greeting.webapp.test {
requires greeting.webapp;
requires spring.test;
requires spring.boot;
requires spring.web;
requires spring.boot.starter.webflux;
requires spring.boot.starter.test;
requires spring.boot.test;
requires spring.boot.test.autoconfigure;
requires org.junit.jupiter;
requires org.junit.jupiter.api;
requires org.junit.jupiter.params;
requires org.junit.jupiter.engine;
requires org.junit.platform.commons;
requires org.assertj.core;
requires mockito.junit.jupiter;
}
And when run the sample test, I got the following errors.
Exception in thread "main" java.lang.IllegalAccessError: class org.junit.platform.launcher.TestIdentifier (in unnamed module #0x6325a3ee) cannot access class org.junit.platform.commons.util.Preconditions (in module org.junit.platform.commons) because module org.junit.platform.commons does not export org.junit.platform.commons.util to unnamed module #0x6325a3ee
at org.junit.platform.launcher.TestIdentifier.from(TestIdentifier.java:56)
at com.intellij.junit5.JUnit5IdeaTestRunner.<clinit>(JUnit5IdeaTestRunner.java:86)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:377)
at com.intellij.rt.junit.JUnitStarter.getAgentClass(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:210)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
And in the test module, I have to move the test scoped deps to compile time to make it work in jmps, how to resolve this issue?
There is no easy way, or no good way at all, imho.
The problem you are having is that you have not configured maven surefire correctly. You can try that - I did and somehow was unlucky, but I did not invest too much time in making it work (neither do I think that will work, but that is a different problem). Instead I configured surefire plugin manually, via:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<argLine>
--add-exports org.junit.platform.commons/org.junit.platform.commons.util=ALL-UNNAMED
--add-exports org.junit.platform.commons/org.junit.platform.commons.logging=ALL-UNNAMED
</argLine>
</configuration>
</plugin>
Overall, I like gradle approach more. You can read on my experience with it here. I also don't think that IDEs (Intellij in my case) have yet proper support to run a single (maven based project) test, unlike gradle. But, to be fair, I only tried that against your repo, so far...
You can also read about a rather neat approach that gradle has taken when you need to declare modules here, with their dedicated plugin.

Java Maven build source and targe is not working

I have JDK 7 and 8 installed in my PC.
I try to set JAVA_HOME to JDK 8 and in the maven pom file, I set to 1.7 as below:
<properties>
<maven.compiler.target>1.7</maven.compiler.target>
<maven.compiler.source>1.7</maven.compiler.source>
</properties>
I got the error below during maven build:
incomparable types: boolean and java.lang.Object
The source code is:
Map mapData = (LinkedHashMap)it.next();
if(true == mapData.get("isTrueOrFalse")){ // java 8 doesn't allow this, it have to be [true == (boolean)mapData.get("isTrueOrFalse")]
xxx
}
I can't change the source code, so I change my JAVA_HOME to JDK 7 and maven pom remain as 1.7. Then I can successfully build via Maven.
My understanding is, by setting the source and target, it should allow me to compile onto lower compatible Java version, but it is not. Can anyone help to explain this?
Apache Maven page says that:
Merely setting the target option does not guarantee that your code actually runs on a JRE with the specified version (...) In the same way, setting the source option does not guarantee that your code actually compiles on a JDK with the specified version
You could try first configuring the plugin directly (instead of what you have on pom.xml):
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<verbose>true</verbose>
<fork>true</fork>
<executable><!-- path-to-javac --></executable>
<compilerVersion>1.7</compilerVersion>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
Lastly, you can try Compiling Sources Using A Different JDK
After so many of searching of Java compatibility post, I found two possible reasons why this is happening:
1) this is a bug in JDK 7, it should not allow JDK 7 to compile this as the type is not match. This is fixed in JDK 8, so even we use the -source=1.7 and -target=1.7, it is not allowed to go through. JDK 1.7 breaks backward compatibility? (generics)
2) this might due to the Java implementation return type not compatible, while using JDK 8 compile to -source=1.7 and -target=1.7, the build path (bootstrap classes) will be still pointing to JDK 8, as so the implementation of Java Map may return different type which cause issue above. Issue about java 8 backward compatibility: new methods in JDK

OpenClover - Getting to work with AspectJ

I'm trying to use Openclover with a project that uses AspectJ and that instruments aspects into its code.
The pom.xml has these dependencies with relation to AspectJ:
...
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
<scope>provided</scope>
</dependency>
</dependencies>
...
And these plugins:
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.openclover</groupId>
<artifactId>clover-aspectj-compiler</artifactId>
<version>1.0.0</version>
</plugin>
<plugin>
<groupId>org.openclover</groupId>
<artifactId>clover-maven-plugin</artifactId>
<version>4.2.0</version>
<executions>
<execution>
<id>clover</id>
<phase>verify</phase>
<goals>
<goal>instrument</goal>
<goal>clover</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
I'm using two plugins to do this: clover-maven-plugin which is a code coverage tool and clover-aspectj-compiler, a wrapper for AspectJ compiler which allows code instrumentation using OpenClover.
The errors I get are the following:
[ERROR] QueryAspect.java:48:0::0 The type QueryAspect is already defined
[ERROR] LogAspect.java:35:0::0 The type LogAspect is already defined
The documentation about this is just too little (or better, none) and I can't seem to make AspectJ work with OpenClover, and there isn't much help on the web.
Thank you
As discussed in our comments, you can just use AspectJ Maven instead of Clover AspectJ. You just need to take a few precautions in order to get it to work:
I like to put AspectJ Maven executions into the process-sources phase in order to make sure the AspectJ compiler kicks in before the normal Java compiler kicked off by Maven Compiler plugin. You could also deactivate Maven Compiler instead as Ajc is a full replacement for Javac. Actually that phase used to be the default in older plugin versions, but it has been changed long ago, which is also mentioned in an answer on SO. See also MASPECTJ-13 for why it was changed and MASPECTJ-92 for why the change was a bad idea.
There is a problem in Maven Compiler, namely the switch useIncrementalCompilation seems to have reversed logic. This is why you need to set it to false in order to make it work. Otherwise it tries to recompile stuff already compiled by AspectJ, breaking aspect weaving. See MCOMPILER-209 and MCOMPILER-194, I explained the problem and its solution there in my posts.
Now the only issue actually related to OpenClover (OC): AspectJ (AJ) does not know anything about OC adding source code to each method in order to enable code coverage. Unfortunately OC also does not know about AJ and also adds code to annotation-style pointcuts defined as empty methods with a #Pointcut annotation. As OC needs to do its magic before AJ compiles, the AJ compiler complains about unexpected code found in the pointcut and stops compilation with an error. There are at least two ways to avoid that:
You can either inline all pointcuts into the respective #Before, #After, #Around etc. advices using them, which usually works, but is not always an option in cases where you need argument binding in pointcuts in order to implement a wormhole pattern like execution(pointcutA()) && cflow(execution(pointcutB(myArgument))).
Or you can exclude all aspects from OC instrumentation, which is easiest if they reside in one package where there are no other Java classes which need to be instrumented. Then you can use a simple exclusion like in your case <exclude>codeaspects/**</exclude>. This is what I was doing in my pull request when fixing your project.
The easiest way is to just rename all aspects from *.java to *.aj, which is the canonical way of naming them anyway. I just tried in your project, and it works beautifully. AspectJ Maven looks for those files anyway, but OC will ignore them, not even calculating their lines of code for missing coverage. You can also get rid of the <exclude> mentioned above, see this commit.
Maybe all of this is automatically taken care of by Clover AspectJ, I never tried. Maybe the author of that compiler wrapper should actually explain what it does and how it works in the documentation, especially how to use it with Maven. Otherwise it does not make much sense to use it.

#Override not working in Maven project

I have several override methods like this:
#Override
public int compareTo(Property p) {
return getText().compareTo(p.getText());
}
As a Java project, it works fine, but as a Maven project, it returns the following error:
The method compareTo(Property) of type Property must override a superclass method
After researching into this, I think I'm suppose to include my JRE System Library (jdk1.6_u25) as a dependency in my POM file, or is this a completely different problem all together?
Many thanks.
You don't need another dependency. But by default, maven uses Java 5 language level, where #Override wasn't allowed for implementing interface methods. That was introduced in 6.
So you must configure the compiler plugin to use language level 6 like this:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
compareTo is a generic method. Generics are not used so compareTo(Object) is the only method you can override.
Please check that:
Maven uses a java to compile that supports generics.
Source-Level is >= 5.
execute mvn -V to see what version of java maven uses to compile.
Regards
Thank you all for your comments, a lot of you stated that Maven used Java 5 by default and could be the cause of the issue, and as a result, I was able to determine the problem through this answer:
Why is javac failing on #Override annotation
The JDK compiler's compliance level was set to 1.5 by default; once I set it to 1.6, the errors were removed.
Many thanks.

PMD coulnd't find ruleset

I'm on creating a maven based java project, which contains the PMD maven plugin. I use my own rule set XML and it works like a charm, except two rule sets: the emptycode and the unnecessary: when I run the build, maven says: "can't find resource". The role definitions look like:
<role ref="rulesets/emptycode" />
and
<role ref="rulesets/unnecessary" />
In every other cases, this kind of definition works. What I found out is that: there is a rule set with the name "unnecessary" under ecmasrcipt category, so maybe this definition needs some suggestion to use java version. I tried multiple thinks, like set language attribute to the ruleset xml node ("JAVA", based on PMD JavaDoc), and some pre-postfix in ref, but it doesn't work and I found no working solution over the web. Does someone has an idea, what I forgot to set, or what I fail? Thanks for any help!
PMD seems to be a fiddly beastie to use from Maven. I've just figured this out with version 3.0 of the plugin - there are two solutions:
The quick-and-dirty solution: put rulesets in your project:
download the PMD jar (http://sourceforge.net/projects/pmd/files/latest/download)
extract lib/pmd-x.x.x.jar
extract from that PMD jar file the rulesets/<type>/<ruleset>.xml files you want to use
place them in a folder under your project - something like ${basedir}/pmd/...
reference them as follows:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<configuration>
<rulesets>
<ruleset>${basedir}/pmd/<ruleset>.xml</ruleset>
</rulesets>
</configuration>
</plugin>
The advantage is this is easy, the disadvantage is if you update the PMD version in future you'll need to remember to update these files.
The nice solution: reference rulesets in pmd-x.x.x.jar.
create a custom ruleset such as: ${basedir}/pmd/custom.xml (see http://pmd.sourceforge.net/pmd-5.0.2/howtomakearuleset.html)
reference the PMD rulesets in the following way: <rule ref="rulesets/java/imports.xml"/>
NB: the path is the path inside pmd-x.x.x.jar (see quick-and-dirty above) with no leading slash
reference your custom ruleset as follows:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<configuration>
<rulesets>
<ruleset>${basedir}/pmd/custom.xml</ruleset>
</rulesets>
</configuration>
</plugin>
The advantage is this will always reference the current PMD rulesets from the PMD jar, the disadvantage is it's a bit fiddly to get right.
To experiment with this until it was working (maven-pmd-plugin version 3.0) I kept running mvn pmd:pmd (<linkXref>false</linkXref> in pom.xml) and tweaked the paths until I stopped getting errors.

Categories

Resources