Eclipse Gradle buildship import sub project compilation error - java

I have project xxxWeb using project xxxAPI. Both projects are sub project of a parent project. Project xxxAPI uses a third-party library jar jar1.jar, which has a class somepackage.ClassA. Project xxxAPI itself also has identical somepackage.ClassA that project xxxWeb intends to use.
However, Eclipse load somepackage.ClassA from jar1.jar instead, resulting in compilation error because jar1/somepackage/ClassA doesn't have the necessary fields like in xxxAPI/somepackage/ClassA.
In xxxWeb project classpath, Eclipse place xxxAPI project to the very end, which probably why the compiler pick jar1/somepackage/ClassA instead of xxxAPI/somepackage/ClassA.
This is not a problem in IntelliJ however.
Is there a cure for this?
The build script work fine, so I this is a question on Gradle's Eclipse plugin, and how to manipulate the generated classpath?

This is a bug of gradle as of version 2.14.1. A workaround is to utilize the hook given by Eclipse Gradle plugin to remove the duplicated classpath entries
eclipse {
classpath {
file {
whenMerged { cp ->
cp.entries = cp.entries.unique{a,b -> a.path <=> b.path}
}
}
}
}

Related

entityName_ cannot be resolved to a variable, error message in eclipse ide?

In my Jhipster generated file entityNameQueryService.java , eclipse indicates the following line as error, but project compiles successfully.
So, this must be the configuration issue with the eclipse ide. Couldn't figure it out myself..
if (criteria.getId() != null) {
specification = specification.and(buildSpecification(criteria.getId(), FRCommunications_.id));
}
The error message is
"FRCommunications_ cannot be resolved to a variable"
For your information, FRCommunications is my entity name.
Does anyone have a fix for this?
For eclipse, After
mvn clean install -nsu
just right click on target/generated-sources/annotation and select "Use as Source Folder"
JPA static metamodel which is used for JPA filtering in JHipster requires generating classes (named like the entity but suffixed with '_') at build time through an annotation processor, this is configured for maven and gradle so you can run a build and it will generate missing classes.
Alternatively, if you don't want to build using maven or gradle see https://docs.jboss.org/hibernate/orm/5.0/topical/html/metamodelgen/MetamodelGenerator.html#_eclipse

Gradle - Class not loaded : org.docx4j.jaxb.Context

I had a maven project with old docx4j dependencies, and I wanted to update to java 9. During the update I changed my project from maven to gradle.
So now I have a gradle project in IntelliJ with this dependencies:
dependencies {
implementation('commons-io:commons-io:2.6')
implementation('javax.xml.bind:jaxb-api:2.4.0-b180725.047')
implementation('org.docx4j:docx4j:6.0.1')
implementation('org.docx4j:docx4j-ImportXHTML:6.0.1')
implementation('org.docx4j:docx4j-export-fo:6.0.1')
testImplementation('junit:junit:4.12')
}
The build is working, but if I want to open a .docx file, with Docx4J.load(...) or WordprocessingMLPackage.load(...) it throws a RuntimeException.
In debug mode I can see this message: Class not loaded : org.docx4j.jaxb.Context
This Context.java file has a static code block like this:
static {
...
}
I think it's gradle specific error, because I created a new maven project with the same code and dependencies as the gradle project, and it works.
Is there any solution for this, or should I use maven in the future too?
There is a Gradle-specific answer at https://stackoverflow.com/a/51235096/1031689
Or to "add module" instead, see for example:
https://www.concretepage.com/questions/531
https://github.com/IntershopCommunicationsAG/jaxb-gradle-plugin/issues/11
Or mac java 9 gradle ClassNotFoundException: javax.xml.bind.JAXBElement when building

In Buildship: how can I substitute a Gradle project with a built jar?

I would like to be a able to get Eclipse to ignore one Gradle project, and instead use a pre-built version of it.
Background
I have a project "parser" written in Scala, and a dozen others written in Java. The weakest link in my tool-set is Scala IDE. I use this plugin to edit & compile Scala code, but unfortunately it breaks the Java (JDT) tooling quite badly in mixed-language projects*.
Specifically: Call-hierarchy is missing results, searches crash and so on. Also Scala IDE appears to have lost funding and the issues sound fairly fundamental, so I'm not holding my breath for these issues to be fixed.
With Maven (m2e) I had a workaround I was quite happy with:
Build as a .jar put into my local .m2 repository:
cd parser; mvn install
In Eclipse, close the "parser" project
"Like magic", m2e simply picked up the most recent 'installed' .jar and used it in place of the closed project.
An awesome answer would be how to get Gradle to do that!
However all I wish for is any solution that meets these...
Requirements
That I can open Project parser when necessary (which is seldom),
to edit and build changes via the Gradle command-line.
I will close it when done.
Other projects use the built .jar from my local .m2 repo.
(It's fine if they always do so.)
The change must not affect others who don't use Eclipse
(ideally) the change can be used by other Eclipse users
Approaches
A similar question had this good answer by #lance-java with a number of general suggestions. I think I can rule out these ideas:
composite build support / multiple repos. Other team members wouldn't think it makes sense to build this project separately, as it is quite closely integrated with the others.
dependency substitution rules - doesn't appear to meet requirement 3.
Something along the lines of lance-java's idea #4 sounds viable. Paraphrasing...
"use the eclipse plugin [in conjunction with] Buildship, e.g. using the whenMerged hook to tweak the generated .classpath [of all the Java projects]."
UPDATE: [18 Apr]: I had hit a brick wall in this approach. Buildship was not putting the built .jar onto the runtime classpath. (UPDATE 2: Now resolved - see my answer.)
Questions
The main question: How can I structure a solution to this, that will actually work & avoid any major pitfalls?
Note that the project itself has a few dependencies, specifically:
dependencies {
compile 'org.scala-lang:scala-library:2.12.4'
compileOnly 'com.google.code.findbugs:jsr305:1.3.9'
antlr 'org.antlr:antlr4:4.5.3'
}
So a sub-question may be: How to pull these in into the other projects without duplicating the definition? (If that doesn't work automatically.)
So the solution was a bit involved. After adding 'maven-publish' to create the library, I then implemented the following to force Eclipse to use the prebuilt library:
subprojects {
// Additional configuration to manipulate the Eclipse classpaths
configurations {
parserSubstitution
}
dependencies {
parserSubstitution module("com.example:parser:${project.version}")
}
apply plugin: 'eclipse'
eclipse {
classpath {
plusConfigurations += [ configurations.pseLangSubstitution ]
file {
whenMerged { cp ->
// Get Gradle to add the depedency upon
// parser-xxx.jar via 'plusConfigurations' above.
// Then this here if we have a dependency on Project(':parser')
// - If so, remove it (completing the project -> jar substitution).
// - If not, remove the .jar dependency: it wasn't needed.
def usesParser = entries.removeAll {
it instanceof ProjectDependency && it.path.startsWith('/parser')
}
def parserJar =
cp.entries.find { it instanceof Library && it.path.contains('parser-') }
if (usesParser) {
// This trick stops Buildship deleting it from the runtime classpath
parserJar ?. entryAttributes ?. remove("gradle_used_by_scope")
} else {
cp.entries.remove { parserJar }
}
}
}
}
So there are 2 parts to this:
Using 'plusConfigurations' felt a bit round-about. I ended up doing this because I could not see how to construct class Library classpath entries directly. However it could well be that this is required to implement the 'transient dependencies' correctly anyway. (See the end of the question.)
The trick to stop Buildship removing the .jar from the runtime classpath (thus deviating from a Gradle command-line launch) was provided to me by a Gradle developer in this discussion.
Usage
The solution works just as I hoped. Every time some code in this library is modified, I execute the following task of mine on the command line (which also does some other code & resource generation steps, in addition to building the parser jar):
./gradlew generateEclipse
Then in Eclipse I press keyboard shortcuts for "Gradle -> Refresh Gradle Projects", Build.
And harmony is restored. :-)
Navigating to the (prebuilt) source of parser works.
If I need to edit the source, I can open the parser project and edit it. Scala-IDE still does a good job for this.
When I'm done I execute the command, close the project and my Java tools are happy.
In parser project
You shoud use the maven-publish plugin with the publishToMavenLocal task
apply plugin: 'maven-publish'
group = 'your.company'
version = '1.0.0'
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
pom.withXml {
def root = asNode()
root.appendNode('name', 'Your parser project name')
root.appendNode('description', 'Your parser project description')
}
}
}
}
Everytime you make a modification, just change the version number if necessary and go with gradle publishToMavenLocal
In other java project using parser
Just use parser as a regular dependency :
repositories {
mavenLocal()
...
}
compile 'your.company:parser:1.0.0'
If my understanding of your situation is good, it should do the trick.

Dependency on generated source set using Gradle Composite Builds and Intellij IDEA

I build my project (call this project B) and some of its upstream dependency projects with Gradle composite builds. One of these upstream projects (call this project A) has an alternate source set configured to avoid producing warnings on generated code.
This is configured like:
sourceSets {
generated {
java {
srcDir "$buildDir/generated-sources/generated/main/java"
}
}
}
dependencies {
compile sourceSets.generated.compileClasspath
compile sourceSets.generated.output
}
compileGeneratedJava.options.warnings = false
jar { from sourceSets.generated.output }
This works fine building with gradle from the command line. But, in IntelliJ Idea, it imports the two source sets as separate modules: A_main and A_generated. It creates a dependency from B_main on A_main, but not on A_generated.
This results in run-time errors when running from IntelliJ IDEA. (B does not directly use any generated classes from A).
How can this be resolved?
The versions I'm using are:
IntelliJ IDEA: 2017.2.5
Gradle: 4.2.1

IntelliJ and Android Gradle dependencies - unable to find module

I have following directory structure:
D:\PROJECT
+---javaGradleProject1
+---javaGradleProject2
+---javaGradleProject3
\---AndroidProject
| build.gradle
| settings.gradle
\---AndroidModule
build.gradle
Android module depends on all of java gradle projects that are at the same level in root directory as AndroidProject.
In AndroidProject/settings.gradle I have:
include ':AndroidModule'
include 'javaGradleProject1'
project(':javaGradleProject1').projectDir = new File(rootDir, '../javaGradleProject1')
include 'javaGradleProject2'
project(':javaGradleProject2').projectDir = new File(rootDir, '../javaGradleProject2')
include 'javaGradleProject2'
project(':javaGradleProject2').projectDir = new File(rootDir, '../javaGradleProject2')
And then in AndroidProject/AndroidModule/build.gradle I have dependencies set like this:
compile project(':javaGradleProject1')
compile project(':javaGradleProject2')
compile project(':javaGradleProject3')
This structure of dependency perfectly works and project builds when I invoke
gradle build
on AndroidProject/build.gradle.
But when I try to synchronize my IntelliJ with current gradle dependency settings I receive
Error: Unable to find module with Gradle path ':javaGradleProject1'
Error: Unable to find module with Gradle path ':javaGradleProject2'
Error: Unable to find module with Gradle path ':javaGradleProject3'
and because of that my project cannot be run from Run Configurations (it does not compile at all in IDE). I was trying to add these dependencies manually by hitting F4 and module dependencies but after synchronization all of my changes are overwritten (actually, IntelliJ just removes it).
Is there anything wrong in my gradle structure?
I have tested it on IntelliJ IDEA 14.1.4 and Android Studio 1.3.
I was able to solve this by deleting the settings.gradle file from every Gradle project that I wanted to use as dependency (clearing the contents of this file was not enough).
NOTE: As I have little knowledge of Gradle and Android Studio, I cannot provide information about why the presence of this file does not allow Android Studio to include the Gradle project as a module.
Add a colon (:) before the names of your modules when you add it in settings.gradle, e.g. for the first one, change this:
include 'javaGradleProject1'
project(':javaGradleProject1').projectDir = new File(rootDir, '../javaGradleProject1')
to this:
include ':javaGradleProject1'
project(':javaGradleProject1').projectDir = new File(rootDir, '../javaGradleProject1')
Now in addition to compiling, IntelliJ / Android Studio should give you code completion.
In my case I had to change the external module name to lowercase only.
Right click project, Select
"Configure Project Subset ..."
and select your module, rebuild your project.
Tried all the available solutions, and in last I have commented the include ':app' in settings.gradle and this resolved the issue in my case
In my case non of the answers above resolved it.
Finally, I went to settings.gradle file and inside the dependencyResolutionManagement block, I changed the repositoriesMode to "PREFER_PROJECT"
repositoriesMode.set(RepositoriesMode.PREFER_PROJECT)
That was all I did and it worked like magic, maybe such can help you too, you can try it out.

Categories

Resources