Gradle: Annotation Processor can't find project dependency - java

I'm fairly new to Gradle and I have a project which uses JPA modelgen. Said project depends on another project which is our own and the annotation processor can't find this dependency. It has no issues resolving external dependencies.
Relevant part of my build.gradle:
dependencies {
compile project(":my-other-project")
//Omitted irrelevant stuff
annotationProcessor 'org.hibernate:hibernate-jpamodelgen:5.4.18.Final'
}
Now I'm probably missing something super simple, but I can't find the cause of this error, which occurs when building:
symbol: class [my-other-class]
location: class [my-class]
C:\[path]\:94: error: cannot find symbol
DataProvider<[my-other-class], String> createDataProvider([my-class] service) {
^
Now when I start the application, it compiles and runs, just without layouting (this is a Vaadin Java application)

Related

Java JPMS: `package xxx is not visible`

I have a simple Java project using the non-modularized dependency "io.prometheus:simpleclient_hotspot:0.16.0". It has been working fine until, for other reasons, I wanted to use the Java module system and add a module-info.java to my project. Once I do that, I start getting the compilation error:
error: package io.prometheus.client is not visible import io.prometheus.client.CollectorRegistry;
^ (package io.prometheus.client is declared in the unnamed module, but module simpleserver does not read it)
The prometheus client library isn't modularized, so it is called an "unnamed module". How do I get access to the packages of such a library? I assume I add a dependency in my module-info.java?
This seems like a basic, common JPMS newbie issue, but after doing lots of searches I can't find the solution to this issue.

Use gradle to include classes from sub-project A in the classpath for sub-project B

I'm very new to gradle and was having problems in a more complicated project which provides context to this overall question, so I decided to create a new, simple project to try to get the concept to work, but I still can't get it to work.
I have one sub-project called core and one sub-project called db. I have a class in the db project called com.kenny.db.DBMain which has a main() function that I want to run. DBMain.main() needs to use com.kenny.core.* classes that are defined in the core project.
I'm able to add a dependency in my db/build.gradle so that it depends on :core, but my code in db isn't able to see the classes from core.
db/build.gradle:
plugins {
id 'java'
}
dependencies {
project(":core")
}
db/src/main/java/com/kenny/db/DBMain.java:
package com.kenny.main;
import com.kenny.core.*;
public class DBMain {
public static void main(String[] args) {
CoreStuff stuff = new CoreStuff();
System.out.println("db test, name="+stuff.name);
}
}
When I try to build DBMain.java, it fails because it can't find com.kenny.core.CoreStuff() which was defined in the core project.
/Users/kenny/projects/gradlewtf/db/src/main/java/com/kenny/db/DBMain.java:3: error: cannot find symbol
import com.kenny.core;
^
symbol: class core
location: package com.kenny
How do I get the classes from core available when compiling code in the db project?
--
Edit: Changed the core project code package to com.kenny.core and the db project code package to com.kenny.db. Still the same problem, the db project isn't getting the core code into the classpath so it cannot compile.
I finally got it to work. I tried following the documentation on the gradle website itself, but at every turn, their example code failed to even compile. That's because you need to already understand gradle in order to realize that you need to change their example code, but they don't really tell how/what you need to change. I mean, they try to tell you inside a paragraph later on, but unless you are already a gradle expert, those instructions don't make much sense.
I added this to my core/build.gradle file:
// this will create a configuration with the name "instrumentedJars"
// that will include the implementation (i.e. my classes and
// classes from dependencies)
configurations {
instrumentedJars {
canBeConsumed = true
canBeResolved = false
extendsFrom implementation, runtimeOnly
}
}
// this will declare an "artifact" (i.e. a produced output)
// for my :core project. It references the configuration name
// "instrumentedJars" and says that it should include the
// outputs of the task named "jar"
artifacts {
instrumentedJars(jar)
}
Then in my project where I need to include those core classes, I added this to my db/build.gradle file:
dependencies {
implementation(project(path: ":core", configuration: 'instrumentedJars'))
}
Then I can build my db project and it is able to find the classes I need. Then when I need to run my main() method, I added a run task to my db/build.gradle:
task run(type: JavaExec) {
dependsOn(":db:compileJava")
mainClass = 'com.kenny.db.DBMain'
classpath = sourceSets.main.runtimeClasspath
}

junit 5 compile as module

I have a question about junit.jupiter. Is it useful to compile the test as module? Something like that?
module usecases {
requires org.junit.jupiter.api;
}
When I try to compile with ant, I get the following error message:
[javac] error: module not found: org.opentest4j
[javac] error: module not found: org.apiguardian.api
I don't understand it because inside the classpath it would compile without problems but in the module-path not?
Both modules and also org.junit.platform.commons are required to satisfy the declarations of org.junit.jupiter.api. See this snippet of the module descriptor:
/**
* Defines JUnit Jupiter API for writing tests.
*/
module org.junit.jupiter.api {
requires transitive org.apiguardian.api;
requires transitive org.junit.platform.commons;
requires transitive org.opentest4j;
exports org.junit.jupiter.api;
...
}
That's why you have to configure your build tool to also provide at least those three modules.
IIRC, the default "JUnit 5" integration of Ant makes use the non-modular junit-platform-console-standalone artifact. Its JAR does contain all required normal classes but no module-info.class files. Therefore, compiling and running on the classpath works out-of-the-box.
More and recent details for using the "JUnitLauncher Task" can be found here: https://ant.apache.org/manual/Tasks/junitlauncher.html

Production code + Test module-info = Unpossible?

I have a mock class with a trivial implementation of a service I provide from a module. I'm using OpenJDK 11.03, gradle 5.2.1 and IntelliJ 2019.2.
In /main/code/myPackage/myService.java I have:
package myPackage;
class myService {
public abstract void someFunction();
}
And in my test/code/somePackage/myMockService I have:
package myPackage;
// no import, they're in the same package.
class myMockService extends myService {
#Override
public void someFunction() { System.out.prinln("Hello World"); }
}
In my main/code/module-info.java I have:
module myModule {
exports somePackage;
}
I've tried several variations on a test/code/module-info.java, without success. For example:
// "open module" lets anyone use reflection within (mostly JUnit 5 in my case)
import myPackage.myService;
import myPackage.myMockService;
open module myTestModule {
exports myPackage;
provides myService with myMockService
}
The above module-info.java spews errors about how "module name myTestModule does not match expected name myModule", "package 'myPackage' is not visible" (from myMockModule.java), explaining "package myPackage is declared in module myModule but module myTestModule does not read it"
On the other hand, with the following module-info.java, I get a different batch of errors (below the code)
import myPackage.myService;
import myPackage.myMockService;
open module myModule {
provides myService with myMockService;
}
Without a requires myModule;, every reference to the main code branch from my test code gives an "error: cannot find symbol". With a requires myModule;, I get an "error: cyclic dependence involving myModule".
So... my tests can't be in a different module. AND they can't be the same module! [long string of expletives deleted]
How do I introduce a mock version of a service in test code rather than creating an entirely different module/gradle sub-project?
Or is this simply a case where that's not possible, and while you can have a separate test module-info, you can't do much with it?
Or is there some way to dynamically load things at runtime such that I don't have to put every little mock service in any module-info, test or otherwise? Such that ServiceLoader.load() will find them. Hmm... perhaps extend ServiceLoader and wrap its usage in main code such that it'll use the right one either in production code or test code...
a) Welcome to "Testing in the Modular World"!
TL;DR https://sormuras.github.io/blog/2018-09-11-testing-in-the-modular-world.html
Having one or more dedicated test modules is good. With all bells-and-whistles, read module-info.java declarations. Those test modules are your main modules' first clients. Just make sure, that your build tool packages all main modules before compiling and running the test modules. Otherwise you don't test your main modules as close as possible to reality — others will consume your main modules as JAR files. So should you. This solves all issues with services and multi-release JARs as well.
Now the interesting part: in-module testing, also named white box testing. Or how do test types residing non-exported packages or package-private types in exported packages? Either use a build that knows how to patch test modules into main modules (or vice versa) at test compile and/or test runtime. Like pro or Bach.java (which I maintain), or in your case of using Gradle, see b)elow part of this answer.
b) Gradle and Java main, test, … modules are not friends out-of-the-box, yet
Best plugin-based solution: https://github.com/java9-modularity/gradle-modules-plugin -- which honors the pass theses java command line options at test runtime module-info.test configuration file (which I invented). Here you basically desribe your test module requirements via verbose command line options, although a perfect DSL already exists: module-info-java ... loop back to a) and the module-aware build tools.
c) IntelliJ IDEA and Java test modules are ... improving!
https://youtrack.jetbrains.com/issue/IDEA-171419 module-info.java support in 2019.3
https://youtrack.jetbrains.com/issue/IDEA-222831 module-info.test support, soon?

JDK compiler fails for "open" module

Using current JDK build 9-ea+143's javax.tools.JavaCompiler tool, I can compile the simple (empty) example module without an error:
module com.foo.bar { }
If I add open as in:
open module com.foo.bar { }
...the compiler error reads:
/module-info.java:1: error: class, interface, or enum expected
open module com.foo.bar {
^
Syntax based on http://cr.openjdk.java.net/~mr/jigsaw/spec/lang-vm.html
Is the current JDK 9 build not up-to-date with this spec or am I missing an option to be passed to JavaCompiler?
To get the newest Jigsaw features, you need to use the Jigsaw EA build (as opposed to the regular EA builds). I created a GitHub repo exploring open packages and modules (to make reflection work) and also wrote about it - it definitely works on b146.

Categories