Java Modules, Gradle project - Problems with external libraries - java

I have a multi module project in IntelliJ, a java library project, using Gradle with quite old versions of libraries
I must say, and now switching to Java 11 (using right now OpenJDK 11.0.2 from https://jdk.java.net/archive/).
I want to modularize that library project, adding to all modules a module-info.java.
I keep getting an error in one of the modules with one of the dependencies, Saxon-HE.
I isolated that module in a separate project (using Gradle 7.6), and modified the build.gradle dependencies step by step as IntelliJ discovered
import errors, while using the latest versions of the dependencies.
The build.gradle of the project looks like this:
plugins {
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}
test {
useJUnitPlatform()
}
The build.gradle of the module looks like this up to the point with the error with Saxon-HE.
plugins {
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1'
implementation group: 'org.jdom', name: 'jdom2', version: '2.0.6.1'
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0'
implementation group: 'commons-io', name: 'commons-io', version: '2.11.0'
implementation group: 'org.slf4j', name: 'slf4j-api', version: '2.0.6'
implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: '4.10.0'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}
test {
useJUnitPlatform()
}
The module-info.java looks like this, I used the recommendations of IntelliJ so it added automatically the requires statements:
module mymodule1 {
requires org.apache.commons.lang3;
requires org.apache.commons.io;
requires org.slf4j;
requires okhttp3;
requires okio;
requires java.xml;
requires org.jdom2;
}
The next import error IntelliJ discovers while building it results because one of my classes has the import statement:
import net.sf.saxon.xpath.XPathFactoryImpl;
Building the project results in the error:
error: package net.sf.saxon.xpath does not exist
import net.sf.saxon.xpath.XPathFactoryImpl;
Looking at https://mvnrepository.com/artifact/net.sf.saxon/Saxon-HE/11.4 I added to build.gradle of the module:
implementation group: 'net.sf.saxon', name: 'Saxon-HE', version: '11.4'
In IntelliJ I can see in the Project navigator view, in External Libraries that there is
Gradle: net.sf.saxon.Saxon-HE:11.4
Saxon-HE-11.4.jar
IntelliJ recommends
Add 'requires Saxon.HE' directive to module-info.java
The module-info.java looks now like this:
module mymodule1 {
requires org.apache.commons.lang3;
requires org.apache.commons.io;
requires org.slf4j;
requires okhttp3;
requires okio;
requires java.xml;
requires org.jdom2;
requires Saxon.HE;
}
After that the error in the particular class using that import statement is gone, IntelliJ doesn't complain.
But when then building the project I get the error
C:\Users\ME\PROJECTS\myproject\mymodule1\src\main\java\module-info.java:9: error: module not found: Saxon.HE
requires Saxon.HE;
^
Removing the requires Saxon.HE and building the project results in the error:
error: package net.sf.saxon.xpath is not visible
import net.sf.saxon.xpath.XPathFactoryImpl;
^
(package net.sf.saxon.xpath is declared in the unnamed module, but module net.sf.saxon.xpath does not read it)
I find this error message weired, because it says but module net.sf.saxon.xpath does not read it, I would rather expect but module mymodule1 does not read it.
I don't know what's going wrong, other external dependencies are not problematic but Saxon-HE is.

I found here Gradle build - add module path a snippet which might solved it, but maybe only partially, so not sure if this answer can be marked as the solution.
I added to the project build.gradle
subprojects {
apply plugin: 'java'
sourceCompatibility = 19
targetCompatibility = 19
compileJava {
doFirst {
options.compilerArgs += [
'--module-path', classpath.asPath,
'-Xmaxerrs', 1000
]
classpath = files()
}
}
}
Now trying to build it (with Gradle 7.6 and OpenJDK 19), it doesn't complain to not finding modules, so far at least, but now I have the next problem which I desribed here Java Modules, Gradle, external dependencies - Modules reading from more then one

Related

How to use gradle 'api' dependency

I tried using the 'api' dependency keyword in my project , but I got this error saying it cannot find method api()
I tried it on a new project. this is the build.gradle file:
plugins {
id 'java'
}
group 'com.test'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
api group: 'com.google.guava', name: 'guava', version: '27.0.1-jre'
}
I am using gradle V4.9.
when I run gradle build I get this:
Could not find method api() for arguments [{group=com.google.guava, name=guava, version=27.0.1-jre}] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler
If I replace 'api' with 'implementation' everything works fine
What am I missing here?
Is there any setting that needs to be done?
The api configuration comes from the java-library plugin, in your build script you have just applied java plugin. See https://docs.gradle.org/current/userguide/java_library_plugin.html
The key difference between the standard Java plugin and the Java Library plugin is that the latter introduces the concept of an API exposed to consumers. A library is a Java component meant to be consumed by other components. It’s a very common use case in multi-project builds, but also as soon as you have external dependencies.
Just apply the java-library plugin (which extends java plugin) and it should work:
plugins {
id 'java-library'
}
For those using kotlin build scripts use the following:
plugins {
id("org.gradle.kotlin.kotlin-dsl")
}

Package 'com.example' reads package 'javafx.beans' from both 'javafx.base' and 'javafx.base'

In module-info.java i get the error
Package 'com.example' reads package 'javafx.beans' from both 'javafx.base' and 'javafx.base'.
Not only does the migration (Java 8 to Java 11) frustrate me slowly but surely, this error does not make any sense to me.
The dependencies part fo my build.gradle:
def springFrameworkVersion = '5.1.2.RELEASE'
def hibernateVersion = '5.3.7.Final'
def junitJupiterVersion = '5.3.1'
dependencies {
compile 'org.transentials:cardhouse-commons:1.1.1'
compile 'ch.qos.logback:logback-classic:1.2.3'
compile "org.springframework:spring-context:$springFrameworkVersion"
compile "org.springframework:spring-jdbc:$springFrameworkVersion"
compile "org.springframework:spring-orm:$springFrameworkVersion"
compile "org.hibernate:hibernate-core:$hibernateVersion"
compile 'org.apache.commons:commons-dbcp2:2.5.0'
compile 'org.apache.commons:commons-lang3:3.8.1'
compile 'commons-io:commons-io:2.6'
compile 'com.h2database:h2:1.4.197'
compile 'javax.xml.bind:jaxb-api:2.3.1'
compile 'com.google.guava:guava:27.0-jre'
compile 'org.flywaydb:flyway-core:5.2.1'
compile 'javax.validation:validation-api:2.0.1.Final'
compile "org.openjfx:javafx-base:11:$platform"
compile "org.openjfx:javafx-graphics:11:$platform"
compile "org.openjfx:javafx-controls:11:$platform"
compile "org.openjfx:javafx-fxml:11:$platform"
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:2.+'
testCompile 'de.saxsys:jfx-testrunner:1.2'
testCompile 'org.apache.commons:commons-text:1.6'
testCompile "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion"
testCompile "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion"
testCompile 'org.hamcrest:hamcrest-all:1.3'
}
And the module-info.java:
module open.terms.client.jfx {
requires org.transentials.cardhouse.commons;
requires com.google.common;
requires org.apache.commons.lang3;
requires org.hibernate.orm.core;
requires java.persistence;
requires slf4j.api;
requires javafx.graphics;
requires javafx.fxml;
requires java.desktop;
}
Can someone explain to me what the compiler wants to tell me by this?
With the required list of dependencies, if you remove all the required modules from the module-info, the IDE will still complain with the same error:
Module '' reads package 'javafx.beans' from both 'javafx.base' and 'javafx.base'
So the problem is not in your module-info, but in your dependencies. If you comment out all of them, except the JavaFX ones, the problem is gone.
This means that some dependency is carrying some unnecessary JavaFX dependency.
I've managed to isolate the problem by commenting only the first dependency:
compile 'org.transentials:cardhouse-commons:1.1.1'
So the question is why is this happening and how can we fix it.
If you go to Maven Central repo it shows the GitHub repo of the dependency, where you can find the build.gradle file and its module-info.
As expected, it uses JavaFX:
compile "org.openjfx:javafx-base:11:$platform"
and it also requires javafx.base in its module-info.
When you consume this artifact with your dependencies you are importing their javafx.base import, along with yours from your JavaFX dependencies and there is the conflict.
The fastest way to solve the issue is just changing this in your build:
compile 'org.transentials:cardhouse-commons:1.1.1'
to this:
compile ('org.transentials:cardhouse-commons:1.1.1') {
exclude group: 'org.openjfx'
}
so you will exclude its JavaFX dependencies and will use yours.
A more permanent fix will be changing the artifact org.transentials:cardhouse-commons's module-info to:
`requires transitive javafx.base`
You can read about the use of transitive here.
An issue should be reported to the author.
Note
As an aside, you can use the javafx gradle plugin to take care of all the related JavaFX parts of the build, simplifying it to:
plugins {
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.5'
}
repositories {
mavenCentral()
}
dependencies {
compile ('org.transentials:cardhouse-commons:1.1.1') {
exclude group: 'org.openjfx'
}
compile files('libs/cardhouse-commons-master-1.1.1.jar')
...
compile 'javax.validation:validation-api:2.0.1.Final'
}
javafx {
modules = [ 'javafx.controls', 'javafx.fxml' ]
}
mainClassName = 'open.terms.client.jfx.Main'
The OpenJFX docs already make use of this plugin.
The error reads, that you've ended up placing same module twice in your modulepath for JavaFX.
The chances are that you might have placed both the jmods for the OpenJFX as well as the OpenJFX SDK/lib on your modulepath.
The JavaFX 11 runtime is available as
a platform-specific SDK
as a number of jmods and
as a set of artifacts in maven central.
Either(one) of these three should be sufficient enough to work with further depending on how you are planning to build your application - modular or non-modular.
Edit 1 [Conceptual Improvement]
In your build.gradle, you should just need to have dependencies over
compile "org.openjfx:javafx-controls:11:$platform"
compile "org.openjfx:javafx-fxml:11:$platform"
since the module, javafx.base and javafx.graphics are transitively present in the module path via javafx-controls anyway. Also, you must ensure, given these dependencies you are not adding any libraries under Project Settings > Libraries.
Edit 2 [Extensible improvement]
Following the documentation at OpenJFX, you can make use of the plugin and get rid of the openjfx dependencies
plugins {
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.5'
}
javafx {
modules = [ 'javafx.controls', 'javafx.fxml' ]
}
dependencies {
// all dependencies except openjfx
}
Edit 3 [Hands on]
The actual culprit in your example is the dependency
compile 'org.transentials:cardhouse-commons:1.1.1'
disabling this fixes the issue. You might want to raise it to the library owner(or fix this if you own it) to ensure that it doesn't bring along javafx.base module along with. To be precise this dependency is bringing in the org.openjfx:javafx-base:linux:11.0.1 as a dependency the reason being clear in their pom.xml dependencies.

Unable to Import From main Java Directory Into test Directory (IntelliJ)

After I attempted to add the AssertJ library to my project for testing, some configuration in my project changed and I cannot import any classes from my main package into my JUnit test package.
My Main Class runs as expected, but I am unable to run any tests requiring Classes from the main package.
I've tried the following:
Removing AssertJ import
Rebuild Project
Refresh All Gradle Projects
Invalidate IntelliJ cache an Restart from Settings
Deleting project locally and re-downloading from GitHub
Removing testing directory and re-adding
Looking at another project that is working it appears to be an issue with my build.gradle file
group 'carpecoin'
version '1.0-SNAPSHOT'
buildscript {
ext.kotlin_version = '1.2.41'
ext.junitJupiterVersion = '5.0.3'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.3'
}
}
apply plugin: 'java'
apply plugin: 'kotlin'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
testImplementation group: 'junit', name: 'junit', version: '4.12'
// JUnit Jupiter API and TestEngine implementation
testCompile("org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}")
testRuntime("org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}")
// To avoid compiler warnings about #API annotations in JUnit code
testCompileOnly('org.apiguardian:apiguardian-api:1.0.0')
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.squareup.retrofit2:adapter-rxjava:2.3.0'
implementation 'io.reactivex.rxjava2:rxjava:2.1.1'
implementation 'com.google.firebase:firebase-admin:6.0.0'
implementation 'com.google.firebase:firebase-database:15.0.0'
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
The line below in the build.gradle file was failing causing the issue above.
implementation 'com.google.firebase:firebase-database:15.0.0'
I updated Firebase to the following and now it is still causing an issue when running tests. It appears to run fine in production:
implementation 'com.google.firebase:firebase-core:16.0.1'

Gradle configuration provided Dependency Ignored in Subproject Build

I have a project with 1 subproject:
projroot/
settings.gradle
build.gradle
mod1/
build.gradle
In mod1/build.gradle there is a "provided" dependency:
apply plugin: 'java'
configurations {
provided
}
repositories {
mavenCentral()
}
dependencies {
provided group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
}
This doesn't seem to work when mod1/src/main/java/One.java imports javax.servlet.ServletContext:
> Task :mod1:compileJava FAILED
/home/x/groot/mod1/src/main/java/One.java:1: error: package javax.servlet does not exist
import javax.servlet.ServletContext;
^
1 error
...
BUILD FAILED in 0s
2 actionable tasks: 1 executed, 1 up-to-date
Using gradle-4.4.1.
Am I defining the dependency in an incorrect place?
Since Gradle 2.12 introduced compileOnly dependencies I rather recommend to use this. Especially when it comes to a Servlet API that will be provided by the servlet container once you deploy your web application on e.g. Tomcat, JBoss, ....
dependencies {
compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
}
provided is a scope used in Maven project that haven't found place in Gradle so far. But compileOnly is very close to Mavens provided scope.

Gradle doesn't find Google Protobuf package

I am trying to setup Google protobuf with netty, but when I start compilation gradle first download google protobuf (at least at the first attempt) but then at compilation it just tells me :
/src/main/java/GameMoveOuterClass.java:1536: error: package com.google.protobuf.GeneratedMessageV3 does not exist
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
here is my build.gradle :
apply plugin: 'java'
apply plugin: 'com.google.protobuf'
repositories {
mavenCentral()
}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.0'
}
}
dependencies {
compile group: 'io.netty', name: 'netty-all', version: '4.1.5.Final'
compile group: 'com.google.protobuf', name: 'protobuf-java', version: '2.4.1'
}
jar {
manifest {
attributes("Main-Class": 'server.Server',
"Class-Path": configurations.compile.collect { it.getPath() }.join(' '))
}
}
If someone knows what's wrong, please let me know
Thanks
You're using the version 2.4.1 of protobuf which doesn't come with GeneratedMessageV3.
Update to a new version of protobuf which include this class like the 3.0.0
dependencies {
compile group: 'io.netty', name: 'netty-all', version: '4.1.5.Final'
compile group: 'com.google.protobuf', name: 'protobuf-java', version: '3.0.0'
}
Using the maven central advanced search for com.google.protobuf.GeneratedMessageV3 it seems that the class is in com.google.cloud:google-cloud-nio:xxx or maybe com.trueaccord.scalapb:protobuf-runtime-scala_yyy:zzz. I'm guessing you'll need to add one of these to your classpath.
I am not familiar with Gradle but it looks to me like you are mixing new protobuf generated code with an older protobuf library, which is not supported. The GeneratedMessageV3 class was added only recently (around 3.0 I believe), and so new generated code that references that class cannot be linked against an older library which does not include it.
In my scenario, both my app and library module should add
implementation 'com.google.protobuf:protobuf-javalite:3.9.1'
even app has a dependency on library

Categories