Since there is no Gradle plugin for axis2 (a wsdl code generator), I called an Ant task in a custom Gradle task.
As of now ./gradlew build generates the code, and ./gradlew clean deletes it. Also, the code is only generated if changes in the input file(s) or in the output directory are detected.
The only problem I'm having is that the code is not generated automatically when the project is imported into an IDE.
How do I need to change the build.gradle.kts below in order to have the IDEs (currently IntelliJ, but I would also like support for Eclipse) generate the code on import?
plugins {
id("base") // needed for delete
}
val axis2 by configurations.creating
dependencies {
axis2("org.apache.axis2:axis2-ant-plugin:$axis2Version")
axis2("org.apache.axis2:axis2-xmlbeans:$axis2Version")
}
val wsdl2Java by tasks.registering {
group = "build"
description = "Creates Java classes and resources from WSDL schema."
inputs.files(fileTree("$projectDir/src/main/resources/wsdl"))
outputs.dir("$projectDir/generated/")
doLast {
ant.withGroovyBuilder {
"echo"("message" to "Generating Classes from WSDL!")
"taskdef"("name" to "codegen", "classname" to "org.apache.axis2.tool.ant.AntCodegenTask", "classpath" to axis2.asPath)
"codegen"(
"wsdlfilename" to "$projectDir/src/main/resources/wsdl/MP12N-H-HOST-WEB-SOAP.wsdl",
"output" to "$projectDir/generated/",
"targetSourceFolderLocation" to "src/main/java",
"targetResourcesFolderLocation" to "src/main/resources",
"packageName" to "de.hanel.com.jws.main",
"databindingName" to "xmlbeans")
}
}
}
val deleteGenerated by tasks.registering(Delete::class) {
delete("$projectDir/generated/")
}
tasks {
compileJava {
dependsOn(wsdl2Java)
}
clean {
dependsOn(deleteGenerated)
}
}
java {
sourceSets["main"].java {
srcDir("generated/src/main/java")
}
sourceSets["main"].resources {
srcDir("generated/src/main/resources")
}
}
You can mark any task or run configuration to be activated before/after Gradle import or IDE make:
I have a working solution now. Both Eclipse and IntelliJ generate the source code on import.
First we add the IDE-specific plugins.
apply {
plugin("idea")
plugin("eclipse")
}
Then we get the corresponding IDE tasks and add our own task, that was defined in val wsdl2Java, as dependency
// find by name (in tasks container), since a module is also called 'idea'
project.tasks.findByName("idea")?.dependsOn(wsdl2Java)
project.tasks.findByName("eclipse")?.dependsOn(wsdl2Java)
The only problem is that apparently Eclipse can't handle
java {
sourceSets["main"].java {
srcDir("generated/src/main/java")
}
sourceSets["main"].resources {
srcDir("generated/src/main/resources")
}
}
But that's a different question.
UPDATE
The code block below tells Eclipse to include the generated sources
eclipse {
classpath {
plusConfigurations.add(configurations.findByName("compile"))
}
}
and this tells IntelliJ to mark the generated, and already included, sources as generated
idea {
module {
generatedSourceDirs.add(file("generated/src/main/java"))
}
}
Related
I am new to Gradle and trying to migrate an existing system build from ant to Gradle.
As part of this I need to run a java program on every file in a directory. Directory contains xml files and the java code will parse and convert .xml to .java files (and these Java files would be build to generate class and package in final jar) after performing some business specific transformation.
below is a function I wrote in Gradle
private runJavaFile(String dirPath) {
FileTree tree = fileTree(dir: dirPath, include: '**/*.xml')
tree.each {
def xmlfile = it.path
def javaFile = it.path.replaceFirst(".xml", ".java")
javaexec { //// getting error on this line
classpath configurations.all
main = 'XmlToJavaParser'
args = ["$xmlfile", "$javaFile", 'Java']
}
}
}
I am calling this function from a Gradle task by passing the dir path which contains the xml files to be parsed.
While running the task, I am getting below error:
> Resolving configuration 'apiElements' directly is not allowed
Any help would be appreciated.
Let me know if any more information is needed.
In Gradle, a configuration represents a group of artifacts and their dependencies. You typically have several configurations depending on what you want to do. For instance, you could have one where you declare which dependencies are needed for compilation, which are only needed at runtime, or which are needed for running a particular Java application.
In your case, you are saying that the classpath to the XmlToJavaParser class is "all configurations combined" and that doesn't really make sense. You are also not allowed to do that as some configurations from the Java plugin are not resolvable like this, which is why you get an error.
So to fix it, you should declare your own configuration for XmlToJavaParser. You can then declare dependencies for it like you normally do. Example (using the Groovy DSL):
configurations {
xmlJavaParser {
canBeResolved = true
canBeConsumed = false
}
}
dependencies {
xmlJavaParser "org.example:xml-java-parser:1.0" // or whatever you need
}
private runJavaFile(String dirPath) {
// ...
javaexec {
classpath = configurations.xmlJavaParser // The configuration is referenced here
main = 'XmlToJavaParser'
args = ["$xmlfile", "$javaFile", 'Java']
}
}
There are also other ways to go about it. But the main point is to not use configurations.all as a classpath.
I have a Gradle build that has some dependencies of the form
compile files('path/to/local/lib.jar')
(the build is being migrated - eventually these will be replaced)
The build failed because one of these paths was incorrectly specified. But it failed due to a compile error - it looked like Gradle silently ignored the missing dependency.
Is there a simple option or switch that will force Gradle to fail the build if any dependency (particularly local file dependencies) cannot be resolved (eg., file missing)?
Edit: to clarify further:
If a dependency cannot be found in the configured repositories, Gradle will fail the build when attempting to resolve them, as expected.
BUT - if a dependency is defined as "compile files ....", and the file specified does not exist at build time, Gradle will IGNORE that error, and attempt compilation anyway. That seems spectacularly wrong-headed and inconsistent default behaviour.
My question is - is there a Gradle option or switch or environment variable or system property that I can set to force Gradle to verify that file dependencies exist? (E.g,, behave in a sane and rational way?)
This is a bit of an old thread, but given that none of the currently proposed solutions actually works, and the solution appears to be trivial (collating two of them), I am leaving it here for future reference.
The point here is that we simply want to ensure that the files do exist, so we can just use the exists() method of the File class:
task ensureDepsExist() {
doLast {
configurations.implementation.canBeResolved(true)
Set<File> impFiles = configurations.implementation.resolve()
impFiles.forEach { f ->
if (!f.exists()) {
ant.fail "${f} could not be found"
}
}
}
}
compileJava.dependsOn ensureDepsExist
The canBeResolved() call is required, or Gradle will complain that configurations dependencies cannot be resolved.
Here's how you can check transitive dependencies using Gradle 7.3 (example: Fail if the project depends on log4j directly or transitively).
Kotlin DSL
configurations {
all {
relsolutionStrategy {
eachDependency {
if (requested.name == "log4j") {
throw RuntimeException("Project depends on log4j")
}
}
}
}
}
Groovy DSL
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
if (details.requested.name == 'log4j') {
throw new RuntimeException("Project depends on log4j")
}
}
}
You could do something as shown below. It is not a built-in Gradle function but does not require code to check each dependency specifically (it checks all in the compile configuration):
apply plugin: 'java'
dependencies {
compile files('lib/abc.jar')
compile files('lib/def.jar')
}
task checkDependencies() {
doLast {
configurations.compile.each { file ->
assert file.exists()
}
}
}
compileJava.dependsOn checkDependencies
To fail the build you can:
ant.fail('message why it failed')
Then you can craft a condition then fail the build with nice message ;)
I would suggest to create a task that will bring the file to the project first with a condition to check if the file is available etc if not then throw a Gradle exception and fail the build with a message, and execute the task first in the execution phase.
I have no chance to test it now but it could be something like this, correct me if any syntax is wrong - but you should get the idea.
def yourDep = $/\path\to\your\depdendency/$
task bringDeps << {
if (yourDep.exists()){
copy {
from yourDep
into $projectDir/depsOrSmthg
}
} else{
ant.fail('message why it failed')
}
}
task ensureDependenciesExist() {
doLast {
configurations.implementation.canBeResolved(true)
DependencySet deps = configurations.implementation.getDependencies()
Set<File> impFiles = configurations.implementation.resolve()
deps.each { d ->
boolean depWasResolved = impFiles.any { impFile -> impFile.name.find(".*${d.name}.*${d.version}") }
if (!depWasResolved) {
println "${d} was not resolved"
assert depWasResolved
}
}
}
}
compileJava.dependsOn ensureDependenciesExist
Gradle provides a default App.java java source file and its test class at the time of creation of project.
I created java class under main:
/src/main/java/some/package/algo/Sort.java
I would like to create a test class that corresponds to it.
/test/main/java/some/package/algo/SortTest.java
I can do that manually but is it possible that Gradle or any gradle command does it for me whenever I create a new regular Java Source file.
I am not using IDE and IDE provide such options.
Similarly any gradle command, If I have a test file than Gradle create java source file under main source.
task createTestForSource {
inputs.dir 'src/main/java'
outputs.dir 'src/test/java'
doLast {
fileTree('src/main/java').visit { FileVisitDetails fvd ->
if (!fvd.directory) {
String sourcePath = fvd.relativePath.asPath
String testPath = sourcePath.replace('.java', 'Test.java')
File testFile = file("src/test/java/$testPath")
if (!testFile.exists()) {
testFile.parentFile.mkdirs()
testFile.text = // do your magic here
}
}
}
}
}
I am writing a JUnit Plug-In Test, which will open a Java Project from the WorkSpace and pass it to a third party library for further processing. This is what I have so far:
#Test
public void testJavaProjectForwarding() {
try {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IWorkspace workspace = root.getWorkspace();
Map<String, IJavaProject> javaProjects = new HashMap<>();
System.out.println("Nr. of projects: " + javaProjects.size());
for(IProject project : workspace.getProjects()) {
if(project.isOpen() && isJavaProject(project)) {
IJavaProject javaProject = JavaCore.create(project);
javaProjects.put(project.getName(), javaProject);
}
}
System.out.println("Nr. of Java projects: " + javaProjects.size());
} catch (CoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I print out first the number of overall projects and second the number of Java projects. Both outputs are, however, 0. This is due to the empty workspace when running a Plug-in Test. My question is: how can I setup the Plug-in Test workspace to include projects? Do I have to do it in the Launch Configuration or can I add them programmatically in the test somewhere? Thanks for your help!
Create a project handle with
org.eclipse.core.resources.IWorkspaceRoot.getProject(String) (returns
IProject)
Load prepared project description:
org.eclipse.core.resources.IWorkspace.loadProjectDescription(IPath)
(returns IProjectDescription, takes a path to .project file as argument)
Actually create a project reference in workspace:
org.eclipse.core.resources.IProject.create(IProjectDescription,
IProgressMonitor)
Open the project: org.eclipse.core.resources.IProject.open(int,
IProgressMonitor)
Example: org.eclipse.ui.internal.wizards.datatransfer.WizardProjectsImportPage.createExistingProject(ProjectRecord, IProgressMonitor). It shows how to copy source project, so that unit tests don't change it. Instead of using precreated (with Eclipse, for example) project description you can create one from scratch.
I'm using Gradle to build my software. However, I find the output it proceduces a bit to minimal. I don't want to use --debug or --info, since that logging is much to verbose. I just want to know what the result in terms of artifacts (zip, jar, dmg, etc) of the Gradle buid is. For example, when I run 'gradle jar', I'd like to print where the jar is created.
I did that using:
jar {
doLast {
println "Jar has been created in ${archivePath}"
}
}
And it nicely prints that the jar has been created in the build/lib directory. However, when I run 'gradle distZip', the artifact is not created in the lib dir, but in the distributions directory. The above however is still printed, but I'd rather not have that: when I run the distZip, I'd like to know where I can find the output of that command, not of every step the distZip depends on.
Never mind, the following will work just nicely:
def artifacts = []
addListener(new TaskExecutionListener() {
void afterExecute(Task task, TaskState state) {
if(task in AbstractArchiveTask) {
artifacts << task.outputs.files.singleFile
}
}
void beforeExecute(Task task) { }
})
addBuildListener(new BuildAdapter() {
void buildFinished(BuildResult result) {
if(artifacts) {
println "\nOutput location: ${artifacts.last()}\n"
}
}
})
This is also available as a gist here.