IntelliJ IDEA "SpringIO" project reports "unable to make the module..." - java

I have been using IntelliJ IDEA for Spring Webflux projects, without any issues. Now (using Ultimate 2019.2.1), build/rebuild reports successful completion, but issues warnings that modules are not able to be created and the Gradle project needs to be re-imported.
"Unable to make the module Xxx, related gradle configuration was not found. Please re-import the Gradle project and try again."
I have re-imported the project from the Gradle view, but this does not resolve the warning (i.e., same warning generated by build process).
I have also tried "Invalidate and Restart" to try clearing caches, again without resolving the warnings.
As a "hail Mary", I have uninstalled-and-reinstalled IntelliJ...again without resolving the warnings.
The project was generated as a "SpringIO" within the IDE, and the only dependency identified during generation was on Spring Webflux.
I have attempted to resolve this through JetBrains support (who have been helpful), but JetBrains seems unable to replicate the warnings.
This is the only source file in the project (i.e., the default "main")...
package foo.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
This is the build.gradle being used (although I had not seen the "dependency management" plugin in prior build.gradle files).
plugins {
id 'org.springframework.boot' version '2.1.7.RELEASE'
id 'io.spring.dependency-management' version '1.0.8.RELEASE'
id 'java'
}
group = 'foo'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webflux'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.projectreactor:reactor-test'
}

It seems that JetBrains latest release (2019.2.1) has one-or-more issues, one of which seems to be the cause for the described behavior. I say "one-or-more issues" because I also discovered that "logging.level" entries in the application.properties file were not being honored by SLF4J/logback.
https://youtrack.jetbrains.com/issue/IDEA-221673

Related

Gradle not resolving dependencies of dependencies

Gradle won't build because it can't resolve dependencies of dependencies. For example, I have a project MyStarterWeb which has a dependency on spring-boot-starter-web:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web:3.0.2'
}
I have a second project, MyFirstEndPoint, that extends/uses/is dependent upon MyStarterWeb:
dependencies {
implementation 'group: 'com.mygroup', name: 'MyStarterWeb', version: '0.0.1-SNAPSHOT'
}
After reading the Gradle docs (which are contradicting, confusing and of little value), I understood that Gradle would resolve all the dependencies for the MyFirstEndPoint project without having to list the spring dependencies listed in MyStarterWeb. But, this is not the case:
error: package org.springframework.boot does not exist
import org.springframework.boot.SpringApplication;
Any help/explanation/guidance/clarification on the poor Gradle docs is greatly appreciated. If there's an RTFM link that I missed, please share
For anyone who runs into this issue with Gradle not resolving transitive dependencies (using Gradle 6.0+) for a self-published artifact/library, the solution was to change the MyStarterWeb project to use the java-library plugin:
plugins {
id 'java'
id 'java-library'
id 'org.springframework.boot' version '3.0.2'
id 'io.spring.dependency-management' version '1.1.0'
}
and then to change the dependencies in MyStarterWeb to use the api configuration instead of implementation configuration.
dependencies {
api 'javax.servlet:javax.servlet-api:4.0.1'
api 'org.springframework.boot:spring-boot-starter-web:3.0.2'
}
That allowed the MyFirstEndPoint project to resolve all transitive dependencies and only have to specify the MyStarterWeb dependency
dependencies {
implementation group:'bla', name: 'MyStarterWeb', version: '0.0.1-SNAPSHOT'
}

Running projects without Eclipse

In my company, plenty of teams (including mine) don't know how to run Spring projects without Eclipse to a point that this is becoming a problem. I've extensively searched around for stuff, but stumbling upon places just saying "press Run" for the project to be ran. Many times that doesn't help us understand the dependencies of legacy projects, and of course, legacy projects have no documentation laying around, or the folks who designed it (or the folks who designed it don't know how to run that without the IDE).
Here is the architecture of the latest one:
Spring, Gradle, Java.
I've tried running this project with ./gradlew run, but the task run doesn't seem supposed to run the application, the task doesn't even exist and the build.gradle file doesn't have it.
This is the build.gradle file:
plugins {
id 'org.springframework.boot' version '2.1.6.RELEASE'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
group = 'com.name'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-actuator'
compileOnly 'org.projectlombok:lombok:1.18.4'
}
This is the Java file that is suppose to be the runner:
package com.company.authApplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class AuthApplication {
public static void main(String[] args) {
SpringApplication.run(AuthApplication.class, args);
}
}
Even if the build.gradle file mentiones mavenCentral(), this is not build for Maven at all, that's just the default structure for it.
Any help is appreciated.

How do you parameterize the Spring Boot Gradle plugin?

We are looking to migrate from Maven to Gradle, and have worked through most of the challenges you would expect for replacing the parent POM concept. There is one sticky point that we haven't figured out yet. We need to specify the version of Spring Boot we are using globally, but I run into invalid build file problems with both of the solutions I've tried:
I tried putting the plugins { id 'org.springframework.boot' version '2.1.17.RELEASE' } declaration in the common build script. Build error, "Only Project and Settings build scripts can contain plugins {} blocks."
I tried calling the common build file to specify the springBootVersion parameter and using that in the plugins declaration. Build Error, "only buildscript {} and other plugins {} script blocks are allowed before plugins {} blocks, no other statements are allowed"
All of this would be easier if I could simply apply plugin: 'org.springframework.boot' but then Gradle can't find the plugin. All but one microservice are on a single version of Spring Boot, and we want to be able to upgrade globally if possible.
Additional Information
I have ~40 microservices plus some libraries used by those services
Separate repository for each of them, so the normal parent/child approach does not work
Maven parent POMs allowed you to publish that POM as it's own resource, and there is no 1:1 equivalent feature in Gradle
Gradle pluginManagement concept also doesn't work for us because it resolves the Spring Boot plugin but the dependency management plugin now can't be found.
My common build script is included here:
repositories {
mavenLocal()
/* Removed our internal repositories */
jcenter()
mavenCentral()
}
apply plugin: 'java'
apply plugin: 'jacoco'
apply plugin: 'maven-publish'
apply plugin: 'io.spring.dependency-management'
group = 'nedl-unified-platform'
/* Required to publish Spring Boot microservices to publish to repository */
configurations {
[apiElements, runtimeElements].each {
it.outgoing.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(jar) }
it.outgoing.artifact(bootJar)
}
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
withJavadocJar()
withSourcesJar()
}
ext {
set('springBootVersion', '2.1.17.RELEASE')
set('springCloudVersion', "Greenwich.SR6")
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
jacoco {
toolVersion = "0.8.5"
reportsDir = file("$buildDir/reports/jacoco")
}
test {
finalizedBy jacocoTestReport // report is always generated after tests run
}
jacocoTestCoverageVerification {
violationRules {
rule {
limit {
minimum = 0.2
}
}
}
}
jacocoTestReport {
dependsOn test // tests are required to run before generating the report
reports {
xml.enabled true
html.destination file("${reportsDir}/jacocoHtml")
xml.destination file("${reportsDir}/jacocoReport.xml")
}
}
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
publishing {
publications {
maven(MavenPublication) {
from components.java
}
}
repositories {
/* excluded for privacy and brevity's sake, our internal Maven repo */
}
}
And that is called by our project build script that I want to parameterize:
plugins {
id 'org.springframework.boot' version springBootVersion
}
apply from: "https://mycentral.repo/project-common/develop/build.gradle"
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'
implementation 'ch.qos.logback:logback-classic'
implementation 'javax.annotation:javax.annotation-api:1.3.2'
implementation 'javax.xml.bind:jaxb-api:2.4.0-b180830.0359'
implementation 'org.glassfish.jaxb:jaxb-runtime:2.4.0-b180830.0438'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
version = '0.0.2-SNAPSHOT'
I think the gap here is that in maven you have the concept of a parent pom, whereas in Gradle you don't. There is no 1:1 mapping to this like you say, but you can have plugins in Gradle, and apply a plugin.
The closest thing you would have is if you developed your own Gradle plugin, which each of your projects could apply. Your custom plugin would then configure Spring Boot among whatever else is common to all your projects. This plugin would define the version of Spring Boot you want all your other projects to use.
You wouldn't get much benefit to a custom plugin if it's only concern is configuring Spring Boot, it would need to do other things as well. It can be difficult to create a Gradle plugin when you don't have allot of experience in it. You lose all the familiar syntax to the build.gradle and you literally have to write code, (there are some similarities but I have found it difficult), I would avoid it if possible.
I would suggest you start off by applying the spring boot plugin directly to one of your microservices projects, get that working, then do another. After you have done a number of them you will then be able to see what is common between them, and if it is indeed worth investing into developing a global plugin. You really need to be careful though because your global plugin has the potential to be both a blessing and curse. It may take away allot of manual work for maintainers, but if you get it wrong it will cause them grief, and then they will want to go back to maven.
I'm not sure if I understand your globally defined Spring version requirement. Unless you are using SNAPSHOT dependencies/plugins (bad don't do that), (or a black magic settings.gralde outside of your repo), you will have to put some version somewhere. As an alternative you could create your own custom task which runs on the check lifecycle which will check the version of spring (or your plugin) and print a warning if it's not the latest version, and encourage the developer to upgrade.
Extra Info
Parameterizing plugins with properties can be done putting your property in gradle.properties as springBootVersion=2.1.17.RELEASE .
I'm not sure I understood your issue perfectly but you should use the Gradle way for sharing configuration : the root project config.
Instead of including the common build script in every project, create a global project and set the configuration here.
root
|
| --- projectA
| --- projectB
| --- projectC
With the according settings.gradle
include 'projectA'
include 'projectB'
include 'projectC'
In the root build.gradle, set up the version
ext.springBootVersion = '2.1.17.RELEASE'
In subprojects using springBoot, let's say projectB, apply the plugin in the sub build.gradle
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
}
}
apply plugin: 'org.springframework.boot'
This example works for me, though I may not understand all of the constraints.
If we abstract the version of Spring Boot behind a fixed URI (e.g. on an internal CI/CD server), then consider this in each project/repo's build.gradle:
buildscript {
repositories {
jcenter()
}
def SPRING_BOOT_VERSION_URI = 'http://localhost:5151/api-server/spring-boot.txt'
ext.springBootVersion = new URL(SPRING_BOOT_VERSION_URI).getText().trim()
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
}
}
apply plugin: 'org.springframework.boot'
apply from: "../common/build.gradle"
I realize the original question states that the apply plugin doesn't work, but it's not clear to me if that precludes this method.
Finally, note that it is easy to expand this beyond a simple text-file to be a more formal JSON specification (tailored to the teams' needs).
If you add this to the root project, all child projects should be able to just import from the same set of Spring Boot dependencies. The magic ingredient is the allprojects block:
buildscript {
repositories {
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
ext {
springBootVersion = '2.3.4.RELEASE'
}
allprojects {
apply plugin: 'java'
apply plugin: 'io.spring.dependency-management'
dependencyManagement {
imports {
mavenBom("org.springframework.boot:spring-boot-dependencies:${springBootVersion}")
}
}
}
apply plugin: 'org.springframework.boot'

Gradle doesn't seem to be resolving my project dependency properly

I'm pretty new to Gradle and am having an issue getting my a module that is dependant on another module to build properly.
So I have the following configuration for my modules.
subprojects {
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
testCompile 'junit:junit:4.10'
}
}
project(':web-service') {
apply plugin: 'war'
dependencies {
compile project(':core')
compile('com.sun.jersey:jersey-server:1.7')
compile('com.googlecode.json-simple:json-simple:1.1.1')
}
}
project(':core') {
dependencies {
compile('log4j:log4j:1.2.17')
}
}
If I try to build my core project everything succeeds as expected.
However, if I try to build the web-service project with the following command:
gradle :web-service:build
It appears to build the core project first as expected but then encounter build errors that indicate that classes that exist in the core module cannot be found.
What gives?
Turns out this was completely my fault. I dug deeper on the error messages that I was getting and found some package does not exist messages at the top. Turns out that my directory structure was not inline with my package names.

Spring 3.2 unit testing with Java based configuration

I am using Spring 3.2 with Java based configuration and have some problems with my unit tests (JUnit 4.8.1). So this is a test runner:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes={TestConfig.class})
public class ManualTest
{
#Autowired
...
Howeever, I am receiving this error:
Caused by: java.lang.IllegalStateException: CGLIB is required to process #Configuration classes. Either add CGLIB to the classpath or remove the following #Configuration bean definitions: [testConfig]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.enhanceConfigurationClasses(ConfigurationClassPostProcessor.java:327)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanFactory(ConfigurationClassPostProcessor.java:222)
As the Spring blog states, Spring 3.2 is inlining CGLIB 3. So why do I receive this error?
I am using Gradle 1.3 as build management tool and STS as IDE. When calling gradle eclipse gradle pulls in the dependencies twice: one time as plain jar and one time as library:
First as plain jar:
and than as library:
In the plain jar section I had still Spring 3.1 configured, while in the library section there was Spring 3.2. So I removed the plain jars and everything was working.
This is my project build.gradle
configurations
{
driver
}
dependencies
{
driver 'com.oracle:ojdbc6:11.2.0'
compile "org.springframework:spring-jdbc:$springVersion"
testCompile 'com.oracle:ojdbc6:11.2.0'
testCompile "org.springframework:spring-test:$springVersion"
testCompile "commons-dbcp:commons-dbcp:$dbcpVersion"
testCompile "junit:junit:$junitVersion"
testCompile "org.slf4j:slf4j-log4j12:$slf4jVersion"
}
sourceSets
{
main
{
java
{
srcDirs 'src/main/java', "$buildDir/generated-sources/"
}
}
}
And the build.gradle from the master project
configure(allprojects)
{
ext.dbcpVersion = '1.4'
ext.springVersion = '3.2.0.RELEASE'
ext.junitVersion = '4.8.1'
ext.slf4jVersion = '1.7.2'
}
subprojects
{
// Artifact settings
group = 'xxx'
version = '1.0-SNAPSHOT'
// Standard plugins
apply plugin: 'java'
apply plugin: 'eclipse'
// Repositories
repositories
{
mavenLocal()
maven
{
url "http://repo.springsource.org/release"
}
mavenCentral()
}
// Standard dependencies
dependencies
{
}
}
I deleted all Eclipse projects and settings and all Gradle temporary files. Then I tried to import the project in Eclipse (Import Gradle project..). This failed with an exception. Then I deleted the Gradle settings within the Eclipse project and after that the import worked.
So I will not use gradle eclipse with version 1.3.
Also the additional source set path did not make its way into the Eclipse project as source path.
I had the same issue. Just add this dependency to your pom.xml file:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
And your unit tests and runtime code should work properly without cglib errors.

Categories

Resources