I have been trying to find the correct settings for IntelliJ's annotation processing in order for it to co-exist with Gradle's build process.
Whenever I build from IntelliJ I cannot get it to recognise the generated sources from the gradle-apt-plugin.
My requirements for my project are:
Building between IntelliJ and Gradle should be seamless and not interfere with the process of each other
I need to use IntelliJ's Create separate module per source set option
I need to use IntelliJ's folder based structure
IntelliJ needs to be able to recognise and autocomplete AutoValue classes
Here are the steps for a MCVE in order to reproduce the issue with IntelliJ 2017.2.4 and Gradle 3.5:
Create a new Gradle project from IntelliJ
Check the Create separate module per source set option
Open build.gradle file:
Add the following plugins block:
plugins {
id 'java'
id 'net.ltgt.apt' version '0.12'
}
Add the following dependencies block
dependencies {
compileOnly 'com.google.auto.value:auto-value:1.5'
apt 'com.google.auto.value:auto-value:1.5'
}
Go to Settings → Build, Execution, Deployment → Annotation Processors
Check the Enable Annotation Processing
Create a class:
#AutoValue
public abstract class GeneratedSourcesTest {
static GeneratedSourcesTest create(String field) {
return new AutoValue_GeneratedSourcesTest(field);
}
public abstract String field();
}
On IntelliJ run Build → Build Project
Open the GeneratedSourcesTest class, on the static factory method, everything compiles fine but I get the error:
cannot resolve symbol ‘AutoValue_GeneratedSourcesTest’
How can I make the AutoValue_GeneratedSourcesTest class accessible from IntelliJ?
After importing your Gradle project under IDEA do the following steps:
Set annotation processing configuration as follows:
Run menu: Build - Build Project
Right click on each new generated folder and select: Mark Directory as - Generated Sources Root so it was marked as follows:
Add /generated to project's .gitignore file
That's a minimal viable configuration which will provide full IDE support for generated classes.
The drawback is, whenever Gradle project gets re-imported the generated folders will need be marked as Generated Sources Root again.
Perhaps this can be improved with adding these paths as source sets under build.gradle.
Sometimes it happens that IDEA modules lose their compiler output path settings in result of the above. It's sufficient to just set it back to their default folders.
The answers are (should be) in the README for the gradle-apt-plugin: https://github.com/tbroyer/gradle-apt-plugin
Namely, also apply the net.ltgt.apt-idea plugin.
Btw, I recommend delegating build/run actions to Gradle in IntelliJ. Sure it's a bit slower, but requires zero setup in the IDE and works reliably. That said, it should also work OK if you don't.
Just have your build.gradle with these and it works fine, no need of touching intellij, source set etc..
plugins {
id 'java'
id "net.ltgt.apt" version "0.20"
}
apply plugin: 'idea'
apply plugin: 'net.ltgt.apt-idea'
group 'abc'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
compile "com.google.auto.value:auto-value-annotations:1.6.2"
annotationProcessor "com.google.auto.value:auto-value:1.6.2"
}
I didn't have to do anything to intellij using maven by adding the optional true tag.
<dependency>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value</artifactId>
<version>1.9</version>
<optional>true</optional>
</dependency>
Related
I'm working on a custom Gradle plugin. For some reason IntelliJ is unable to find the sources of the gradle-api artifact and only shows the decompiled .class file. I am already using the -all distribution of the Gradle Wrapper (which includes some sources, but apparently not the ones I need right here). Clicking Download... results in an error:
Sources not found: Sources for 'gradle-api-6.5.1.jar' not found
How do I correctly attach/choose sources for gradle-api in IntelliJ?
EDIT:
I have a minimal Gradle plugin with code like that (taken from the official samples):
plugins {
id 'java-gradle-plugin'
}
repositories {
jcenter()
}
dependencies {
testImplementation 'junit:junit:4.13'
}
gradlePlugin {
// ...
}
According to this excellent manual you should add gradleApi() as a runtimeOnly dependency:
dependencies {
//...
runtimeOnly(gradleApi())
I guess that, the default Intellij config use gradle from gradle-wrapper.properties file will use /gradle/wrapper/gradle-wrapper.jar, but it doesn't contain source code. what you need is a jar like gradle-wrapper-all.jar. But I don't know how to let Gradle redownload that. Just setting Wrapper.DistributionType.ALL is not working.
Solution
set Wrapper.DistributionType.ALL
wrapper {
jarFile = file(System.getProperty("user.dir") + '/gradle/wrapper/gradle-wrapper.jar')
gradleVersion = '6.7.1'
distributionType = Wrapper.DistributionType.ALL
}
I download Gradle, and use it. Set two things here and refresh it.
Here is the source code, the version is right and with all in the name (gradle-6.7.1-all):
delete gradle dir
run "gradle wrapper"
check the suffix "-all" in the file gradle/wrapper/gradle-wrapper.properties
sample:
distributionUrl=https://services.gradle.org/distributions/gradle-7.5-all.zip
I run into confusion while trying to set a com.vaadin:vaadin-spring-boot-starter Gradle project into production mode.
The project is part of a multi-module project and its (simplified) build.gradle file looks like this:
buildscript {
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
dependencyManagement {
imports {
mavenBom "com.vaadin:vaadin-bom:${vaadinVersion}"
}
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-actuator")
compile("com.vaadin:vaadin-spring-boot-starter")
// ... futher more
}
I've found several projects and documentation focusing this topic, such as:
Vaadin Maven Plugin
Flow Maven Plugin
Gradle Vaadin Flow Plugin
Setting Flow into Production Mode with Maven
My current state is that I added vaadin.productionMode=true to the application.yaml file, which causes the following error on HTTP GET:
Failed to find the bundle manifest file 'frontend://vaadin-flow-bundle-manifest.json' in the servlet context for 'ES6' browsers. If you are running a dev-mode servlet container in maven e.g. jetty:run change it to jetty:run-exploded. If you are not compiling frontend resources, include the 'vaadin-maven-plugin' in your build script. Otherwise, you can skip this error either by disabling production mode, or by setting the servlet parameter 'original.frontend.resources=true'.
So in general, I think that I'm on the right way.
Setting the servlet parameter 'original.frontend.resources=true' removes the error, but it seems like a work-around to me, thus I want to avoid it.
Disabling production mode is obviously not an option :-)
So my question is: How can I include the vaadin-maven-plugin in my Gradle build script. As I am using Flow only, should I rather use the flow-maven-plugin?
Update 1: I want to set a Spring Initializr Gradle project with Vaadin dependency into production mode. I do not want to create a new gradle-vaadin-flow-plugin project.
The Gradle equivalent of vaadin-maven-plugin would be com.devsoap.vaadin-flow (1), and you also need to configure vaadin { productionMode = true } in build.gradle (2)
It's also possible to configure the gradle property so that it depends on a build time parameter, as explained here: configure vaadin.productionMode = findProperty('productionMode') ?: false in build.gradle, and add a placeholder in the #VaadinServletConfiguration that will be preprocessed when building the project.
I'm using gradle as the JavaFX plugin.
Everything works perfectly even after building and runnig the excecutable at distribution/, except with one class: CloseableHttpClient
For several purposes I create the following object like this:
CloseableHttpClient client = HttpClients.createDefault();
Running the program in the IDE is no problem, everything works fine. But if I build and try to run the .exe-File I get the following Throwable-StackTrace:
java.lang.NoClassDefFoundError: Could not initialize class org.apache.http.conn.ssl.SSLConnectionSocketFactory
at org.apache.http.impl.client.HttpClientBuilder.build(HttpClientBuilder.java:955)
at org.apache.http.impl.client.HttpClients.createDefault(HttpClients.java:58)
at ch.itcb.tools.lom.util.JsonSimpleUtil.http(JsonSimpleUtil.java:29)...
I really don't understand that. How can it be that just this class doesn't get found, but all my other classes do?
My build.gradle file:
apply plugin: 'java'
apply plugin: 'eclipse'
apply from: 'javafx.plugin'
sourceCompatibility = 1.8
version = '0.1'
jar {
manifest {
attributes 'Implementation-Title': 'LogoffManager',
'Implementation-Version': version
}
}
repositories {
mavenCentral()
}
dependencies {
compile fileTree(dir: 'lib', include: ['*.jar'])
compile 'ch.qos.logback:logback-classic:1.1.3'
compile 'org.apache.httpcomponents:httpclient:4.5.1'
compile 'com.googlecode.json-simple:json-simple:1.1'
compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
testCompile group: 'junit', name: 'junit', version: '4.+'
}
test {
systemProperties 'property': 'value'
}
uploadArchives {
repositories {
flatDir {
dirs 'repos'
}
}
}
Please write a comment if you need more information. Thx.
it's a good question, which I came across just now while researching examples of the many ways Java developers can end up with class path fun :-)
I started with a minimal version of your build.gradle (including only what's directly relevant), specifically:
plugins {
id 'java'
}
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
jar {
manifest {
attributes 'Main-Class': 'com.oliverlockwood.Main'
}
}
dependencies {
compile 'org.apache.httpcomponents:httpclient:4.5.1'
}
My 'Main' class, in this context, uses your code example, i.e.:
package com.oliverlockwood;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
public class Main {
public static void main(String[] args) {
CloseableHttpClient client = HttpClients.createDefault();
}
}
At this stage, I can run gradle clean build followed by java -jar build/libs/33106520.jar (my project was named after this StackOverflow question) and I see this:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/impl/client/HttpClients
at com.oliverlockwood.Main.main(Main.java:8)
Caused by: java.lang.ClassNotFoundException: org.apache.http.impl.client.HttpClients
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
This is subtly different from your error, but before we dig and reproduce that, let me emphasise something: both this error and the one you're seeing are caused at runtime when the classloader is unable to find a class that it needs. There's quite a good blog post here with some more details about the difference between compile-time classpath and runtime classpaths.
If I run gradle dependencies I can see the runtime dependencies for my project:
runtime - Runtime classpath for source set 'main'.
\--- org.apache.httpcomponents:httpclient:4.5.1
+--- org.apache.httpcomponents:httpcore:4.4.3
+--- commons-logging:commons-logging:1.2
\--- commons-codec:commons-codec:1.9
I added these manually one-by-one to my runtime classpath. (For the record, this isn't generally considered good practice; but for the sake of the experiment, I copied these jars to my build/libs folder and ran with java -cp build/libs/33106520.jar:build/libs/* com.oliverlockwood.Main. Interestingly enough, this wasn't able to reproduce your exact problem. To recap:
Without org.apache.httpcomponents:httpclient available at runtime, then we fail because the HttpClients jar is not found.
With org.apache.httpcomponents:httpclient:4.5.1 available at runtime, then your problem does not manifest - and I note that the class your build fails to find (org.apache.http.conn.ssl.SSLConnectionSocketFactory) is part of this same Apache library, which is very suspicious indeed.
My suspicion is then that your runtime classpath contains a different version of the Apache httpclient library. Since there's a whole lotta versions out there, I'm not going to test every single combination, so I will instead leave you with the following advice.
If you want to fully understand the root cause of your issue, then identify exactly which jars (including their versions) are present in your error-case runtime classpath, including any jars that are packaged inside yours if you're creating a fat jar (more on this in point 3). It'd be great if you shared these details here; root cause analysis usually helps everyone to understand better :-)
Where possible, avoid using dependencies in the manner of compile fileTree(dir: 'lib', include: ['*.jar']). Managed dependencies based on a repository such as Maven or JCenter are much easier to work with consistently than dependencies in a random directory. If these are internal libraries that you don't want to publish to an open-source artifact repository, then it may be worth setting up a local Nexus instance or similar.
Consider producing a "fat jar" instead of a "thin jar" - this means that all runtime dependencies are packaged in the jar that you build. There's a good Shadow plugin for Gradle that I'd recommend - with this in place in my build.gradle, and running gradle clean shadow, I was able to run java -jar just fine without needing to manually add anything to my classpath.
For Spring boot users, this can be solved with one line of code. I am using Gradle/Kotlin, so:
id("org.springframework.boot") version "2.5.5"
inside the plugins {} section of your build.gradle.kts
For more information visit the Spring Boot Gradle Plugin Reference Guide.
For my case, I turned on my InteliJ after 3 months, got some runtime errors like noclassdeffounderror. I have to *** refresh gradle ***, then the errors are gone.
Suppose we have a multi-project build. Eventually the entire project is bundled into a war. We know the web container will provide some utility jars, say, some logging-related jars, so we want to use a provided kind of scope. The war plugin offers the nice providedCompile and providedRuntime configuration. However, we want to use the war plugin only in the subproject that creates the war. So, the problem is, how can we use something like providedCompile and providedRuntime in other sub-projects? Ideally, we want to apply that scope to the logging jars in a subprojects {} closure.
update
My scenario is like below.
In the root build.gradle, I have something like this:
subprojects {
apply plugin: 'groovy'
apply plugin: 'maven'
dependencies {
compile 'org.slf4j:slf4j-api:1.7.7' // already provided by the servlet container
compile 'javax.servlet:javax.servlet-api:3.1.0' // already provided by the servlet container
runtime 'ch.qos.logback:logback-classic:1.1.2' // already provided by the servlet container
runtime 'ch.qos.logback:logback-core:1.1.2' // already provided by the servlet container
...
These dependencies are used not just by the war sub-project, but they should be excluded in the war. Therefore, I need some mechanism to achieve this.
BTW, I have already worked out a solution.
There are a couple of ways to achieve a provided scope.
Option 1
Create a custom configuration provided. For example:
configurations {
provided
}
sourceSets.test {
runtimeClasspath += configurations.provided
}
The downside of this approach is that IDEs, for instance, IntelliJ IDEA, probably don't understand custom configuration and hence are not able to pull dependencies correctly. This happened to me with IntelliJ IDEA.
Option 2
Use the predefined compile and runtime configurations. Then, in the build.gradle of the war sub-project, filter out the jars of your choice. For example,
war {
Set exclusions = ['slf4j-api-1.7.7.jar', 'javax.servlet-api-3.1.0.jar',
'logback-classic-1.1.2.jar', 'logback-core-1.1.2.jar'] as Set
classpath = classpath.filter { file ->
!exclusions.contains( file.name )
}
}
With gradle 2.12, it is possible to use compileOnly when using java plugin.
https://docs.gradle.org/2.12/release-notes#support-for-declaring-compile-time-only-dependencies-with-java-plugin
I've used the Intellij UI Designer to create forms for a project. Everything works fine when I'm building with idea as it handles compiling the forms for me, but as we recently switched to using Gradle for building it hasn't been possible to produce an executable jar file yet.
My google-fu has led me to several posts that explains that an ant script is needed to compile (eg link, link2, link3 ,and the one i ended on following: link4)
My project is a multi-module setup.
root build.gradle
subprojects {
apply plugin: 'java'
apply plugin: 'idea'
repositories {
mavenCentral()
}
}
supproject build.gradle
apply plugin:'application'
mainClassName = "dk.OfferFileEditor.OfferFileEditorProgram"
configurations {
antTask
}
dependencies {
compile 'org.json:json:20140107'
compile project(":Shared:HasOffers Api")
//dependencies for java2c
antTask files('../../lib/javac2-13.1.1.jar', '../../lib/asm4-all-13.1.1-idea.jar', '../../lib/forms_rt-13.1.1.jar')
antTask group: 'org.jdom', name: 'jdom', version: '1.1'
}
task compileJava(overwrite: true, dependsOn: configurations.compile.getTaskDependencyFromProjectDependency(true, 'jar')) {
doLast {
println 'using java2c to compile'
project.sourceSets.main.output.classesDir.mkdirs()
ant.taskdef name: 'javac2', classname: 'com.intellij.ant.Javac2', classpath: configurations.antTask.asPath
ant.javac2 srcdir: project.sourceSets.main.java.srcDirs.join(':'),
classpath: project.sourceSets.main.compileClasspath.asPath,
destdir: project.sourceSets.main.output.classesDir,
source: sourceCompatibility,
target: targetCompatibility,
includeAntRuntime: false
}
}
But even though the compilation is successfull, a Nullpointer exception is thrown the first time I try to access one of the fields the UI Designer created. So something is not being compiled correctly.
I'm probably missing some setting, but after unsuccesfully pouring several hours into forums and google I still haven't found any solution.
So I made this a lot more complicated than needs be.
To make it work you need to change two things in your project.
A setting in IDEA 13.1.5
Settings -> GUI Designer -> Generate GUI into: Java source code
This makes IntelliJ IDEA add 3 methods into the bottom of your forms:
$$$setupUI$$$()
$$$setupUI$$$()
$$$getRootComponent$$$()
If they are missing try recompiling your project after you change the setting.
Add the missing classes
Intellij has a jar called forms_rt.jar, and I found mine in {IntelliJ IDEA Root}\lib. And renamed it to "forms_rt-13.1.1.jar"
This needs to be included during compile time to your project. If you are using Gradle as I did you could copy it to {project root}/lib and add a flatfile repository like so:
repositories {
mavenCentral()
flatDir dirs: "${rootDir}/lib"
}
After that you need to include it in your project gradle file:
dependencies {
compile name: 'forms_rt', version: '13.1.1'
}
After that it should be possible to build it both in IntelliJ IDEA and Gradle.
IntelliJ IDEA 2019.1
I found this issue still exists. It's at least somehow documented now:
If your build actions are delegated to Gradle, GUI Designer will not generate Java source code.
So by disabling the according setting
Build, Execution, Deployment | Build Tools | Gradle | Runner | Delegate IDE build/run actions to gradle
I was able to build and run the project successfully. Note that I didn't need any other settings or additional libraries from the answers above. I let Generate GUI into be set to Binary class files.
The forms_rt library is in mavenCentral.
http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22forms_rt%22
Once you have configured IntelliJ to update the SourceCode it is sufficient to just add the library to the dependencies in your build.gradle.
dependencies {
compile 'com.intellij:forms_rt:7.0.3'
}
Idea 2019.2
It seems like IntelliJ changed the settings UI when updating from 2019.1 to 2019.2, as the menu entry mentioned by Tom isn't there anymore.
I got it fixed by setting Build and run using: to IntelliJ Idea. I also changed Run tests using: to IntelliJ Idea to avoid problems while testing.
Both settings are located under File | Settings | Build, Execution, Deployment | Build Tools | Gradle.
I figured out an updated version of the gradle build workaround for a new project - https://github.com/edward3h/systray-mpd/blob/master/build.gradle
Probably won't use the form designer again though.
These are the relevant parts:
repositories {
mavenCentral()
maven { url "https://www.jetbrains.com/intellij-repository/releases" }
maven { url "https://jetbrains.bintray.com/intellij-third-party-dependencies" }
}
configurations {
antTask
}
dependencies {
implementation 'com.jetbrains.intellij.java:java-gui-forms-rt:203.7148.30'
antTask 'com.jetbrains.intellij.java:java-compiler-ant-tasks:203.7148.30'
}
task compileJava(type: JavaCompile, overwrite: true, dependsOn: configurations.compile.getTaskDependencyFromProjectDependency(true, 'jar')) {
doLast {
project.sourceSets.main.output.classesDirs.each { project.mkdir(it) }
ant.taskdef name: 'javac2', classname: 'com.intellij.ant.Javac2', classpath: configurations.antTask.asPath
ant.javac2 srcdir: project.sourceSets.main.java.srcDirs.join(':'),
classpath: project.sourceSets.main.compileClasspath.asPath,
destdir: project.sourceSets.main.output.classesDirs[0],
source: sourceCompatibility,
target: targetCompatibility,
includeAntRuntime: false
}
}
The dependency versions for jetbrains libraries are found via https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html?from=jetbrains.org#using-intellij-platform-module-artifacts and https://www.jetbrains.com/intellij-repository/releases/