Maven: how to pass parameters between Mojos? - maven-2

How do I program one Mojo to set another Mojo's configuration? For example: Mojo A requires configuration parameter A.foo to be defined. A user can either specify A.foo manually or run plugin B which will calculate the value for him/her.

Answering my own question:
It's possible to access a plugin's configuration or project-wide properties at runtime using a MavenProject instance:
/**
* The maven project.
*
* #parameter expression="${project}"
* #readonly
*/
private MavenProject project;
You can then access a plugin's configuration at runtime:
private Plugin lookupPlugin(String key)
{
List plugins = getProject().getBuildPlugins();
for (Iterator iterator = plugins.iterator(); iterator.hasNext();)
{
Plugin plugin = (Plugin) iterator.next();
if(key.equalsIgnoreCase(plugin.getKey()))
return plugin;
}
return null;
}
...
Xpp3Dom configuration = (Xpp3Dom) Plugin.getConfiguration()
configuration.getChild("parameterName"); // get parameter
configuration.addChild(new Xpp3Dom("parameterName")); // add parameter
...
Note: Any configuration changes are discarded at the end of the current phase.
Source: Best way to access the runtime configuration of a maven plugin from a custom mojo?
Alternatively, you can get/set project-wide parameters using MavenProject.getProperties().

I guess the maven way would be to set a property in the first Mojo and to access it from the other Mojo.

This turns out to be a tricky thing to do mostly due to the timing of "configuration" of the plugins by the Maven runtime. Changing the "configuration" from getBuildPlugins is usually not going to work.
The best method is default-value if you are writing the target plugin, otherwise use properties.
With properties, but you have to be careful about how you use the properties. The caution is to realize that if your POM (or any parent) defines a value for a property, then the ${property} reference will be replaced when the POM is loaded. However if there is no "property" property then the ${property} reference stays and is only replaced with a null value at the last possible moment.
"default-value" is also evaluated at the last possible moment, and I think this is a safer solution because there is a logical reason why it must be evaluated at the last possible moment, where-as the non-existent property may just be an implementation detail that could change in future versions of Maven.
In my case I had to resort to properties because I wanted to control the "classesDirectory" of the surefire plugin. I wanted it to continue to default to ${project.build.outputDirectory} when Cobertura was not run, but when Cobertura was run I wanted it to use ${project.build.outputDirectory}/generated-classes/cobertura.
Define in your plugins section:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<classesDirectory>${instrumentedClassesDirectory}</classesDirectory>
</configuration>
</plugin>
Then in the "source" plugin:
getProject().getProperties().put("instrumentedClassesDirectory", coberturaDir);
And make sure under no circumstances ever put anything like the following in any POM:
<properties>
<instrumentedClassesDirectory>${project.build.outputDirectory}</instrumentedClassesDirectory>
</properties>
because if you do, even though the value of the property is set by your source plugin, your destination plugin will not see the value. You can ignore this last caveat if your using a property passed into the default-value of the source plugin, but as said in my case that would not work because I did not want to change the value of project.build.outputDirectory.

Related

Avro generated class: Cannot access class 'Builder'. Check your module classpath for missing or conflicting dependencies

Running
val myAvroObject = MyAvroObject.newBuilder()
results in a compilation error:
Cannot access class 'MyAvroObject.Builder'. Check your module classpath for missing or conflicting dependencies
I am able to access other MyAvroObject variables. More precisely, methods such as
val schema = MyAvroObject.getClassSchema()
val decoder = MyAvroObject.getDecoder()
compiles fine. What makes it even stranger is that I can access newBuilder() in my test/ folder, but not in my src/ folder.
Why do I get a compile error when using newBuilder()? Is the namespace of the avro-schema used to generate MyAvroObject of importance?
Check your module classpath generally means, that your dependencies (which you didn't provide) are messed up. One of them should read implementation instead of testImplementation, in order to have the method available in the main source-set, instead of only the test source-set - but this may well have to do with the input classes, the output location of generated classes, or annotations alike #VisibleForTesting (just see what it even generates). Command gradlew can also list the dependencies per configuration. The builder seems to be called org.apache.avro.SchemaBuilder... there's only avro-1.11.0.jar & avro-tools-1.11.0.jar. With the "builder" design pattern, .newBuilder() tries to return inner class Builder.
had the same problem today and was able to solve it by adding the following additional source folder
<sourceDir>${project.basedir}/target/generated-sources/avro</sourceDir>
to the kotlin-maven-plugin.

idea `org.jetbrains.plugins.go` not found

I had this problem when I was developing the GoLand plug-in and install plugin from build jar Plugin Gorm Generator depends on unknown plugin com.intellij.velocity
<depends>org.jetbrains.plugins.go</depends>
build.gradle:
intellij {
version '2020.2.1'
sandboxDirectory = "${rootProject.rootDir}/idea-sandbox"
type 'IU'
plugins = ['java', 'DatabaseTools', 'Velocity']
updateSinceUntilBuild false
setPlugins("org.jetbrains.plugins.go:202.7319.5")
}
i'm not find
You're setting the plugins list twice - by assigning an array to the plugins property and calling setPlugins method. That makes your first array simply overwritten by the Go dependency.
Try with the first approach only and simply append the Go entry at the end of your array.

Unused properties in IntelliJ

I am having a problem with IntelliJ inspection: It is indicating that all of my properties are unused (see the image). This is untrue, because all my properties all correctly used in spring boot project. I am using IntelliJ Community Edition 2016.1.4
If you want to ignore all warnings in a specific file. We just have to add this at the first line :
# suppress inspection "UnusedProperty" for whole file
If you just want to ignore a warning for a single property, you can add this line before the property :
# suppress inspection "UnusedProperty"
Idea -> Preferences -> search "unused" or "Inspections" -> uncheck "Unused Property " under "Properties Files"
Maybe the plugin is not supporting this feature/annotation which Intellij is then able to resolve. But you could write your own method for that.
So you have to create a method which calls the method which is not capable of creating the connection. The created method has to make us of the #PropertyKey Annotation which will allow Intellij to see the connection for your method and resolve the not used problem you have.
private static final String BUNDLE_NAME = "application";
public static void newMethod(#PropertyKey(resourceBundle = BUNDLE_NAME) String key) {
oldMethod(key) //replace oldMethod with your method
}
By calling the method foo it will detect the property connection to the property file if your resources are allocatable.
newMethod("your.awesome.key")
add library to pom.xml file problem will be solved
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.2</version>
</dependency>
Use final String variable to define the property's key REGION_CONFIG_KEY,
Invoke the property's key in #Value("${" + REGION_CONFIG_KEY + "}",
So the problem will be fixed

Programmatically having ivy fetch sources

We have a custom build tool which is dependent on the ivy functionality to resolve dependencies. The configuration of the dependencies is not an ivy.xml file, but a custom configuration that allows for.. well, irrelevant. The key is that we're using ivy programmatically.
Given a dependency (group id, artifact id, version), we create a ModuleRevisionId:
ModuleRevisionId id = ModuleRevisionId.newInstance(orgName, moduleName, revisionName);
followed by a ModuleDescriptor. This is, I'm guessing, where I'm not convincing enough to inform ivy that I want both the target library jar file as well as the sources. I'm just not sure what a DependencyConfiguration is vs. just a 'configuration' when creating a ModuleDescriptor.
DefaultModuleDescriptor md
= new DefaultModuleDescriptor(
ModuleRevisionId.parse("org#standalone;working"),
"integration",
new java.util.Date());
DefaultDependencyDescriptor mainDep
= new DefaultDependencyDescriptor(id, /* force = */ true);
mainDep.addDependencyConfiguration("compile", "compile");
mainDep.addDependencyConfiguration("compile", "sources");
md.addDependency(mainDep);
md.addConfiguration(new Configuration("compile"));
md.addConfiguration(new Configuration("sources"));
Nor do I really understand the above vs. RetrieveOptions vs. ResolveOptions.
I need a drink.
Ok, so it took a while, but I finally wrapped my head around some of this.
// define 'our' module
DefaultModuleDescriptor md
= new DefaultModuleDescriptor(ModuleRevisionId.parse("org#standalone;working"),
/* status = */ "integration",
new java.util.Date());
// add a configuration to our module definition
md.addConfiguration(new Configuration("compile"));
// define a dependency our module has on the (third party, typically) dependee module
DefaultDependencyDescriptor mainDep = new DefaultDependencyDescriptor(md, dependeeModuleId, /* force = */ true, false, true);
mainDep.addDependencyConfiguration("compile", "default");
mainDep.addDependencyConfiguration("compile", "sources");
// define which configurations we want to resolve (only have 1 in this case anyway)
ResolveOptions resolveOptions = new ResolveOptions();
String[] confs = new String[] {"compile"};
resolveOptions.setConfs(confs);
resolveOptions.setTransitive(true); // default anyway
resolveOptions.setDownload(true); // default anyway
ResolveReport report = ivy.resolve(md, resolveOptions);
This pulls down both the default jar as well as the sources target. Note that ivy has an issue where it won't transitively pull sources, though it will transitively pull 'main' jars. So you only get the sources for immediate dependency defined here, not the sub dependencies.
One other weakness I'm trying to figure out is this assumes the target dependency has a 'sources' configuration. I'd rather tell it to get any artifacts of type sources/source/src. Haven't figured that one out yet.

Gradle / Groovy properties

I would like to control 'global' config in Gradle build scripts using external property files on each build machine (dev, ci, uat,...) and specify the filename with a command line argument.
e.g. gradle -DbuildProperties=/example/config/build.properties
I specifically don't want to use gradle.properties as we have existing projects that already use this approach and (for example) we want to be able to amend database urls and jdbc drivers without having to change every project.
So far have tried:-
Properties props = new Properties()
props.load(new FileInputStream("$filename"))
project.setProperty('props', props)
which works but has a deprecated warning, but I can't figure out how to avoid this.
Have also tried using groovy style config files with ConfigSlurper:-
environments {
dev {
db.security {
driver=net.sourceforge.jtds.jdbc.Driver
url=jdbc:someserver://somehost:1234/some_db
username=userId
password=secret
}
}
}
but the colons and forward slashes are causing exceptions and we don't want to have to mess up config with escape characters.
There must be a non-deprecated way to do this - can anyone suggest the 'right' way to do it?
Thanks
You can get rid of the deprecated warning quite easily. The message you got probably looks something like this:
Creating properties on demand (a.k.a. dynamic properties) has been deprecated and is scheduled to be removed in Gradle 2.0. Please read http://gradle.org/docs/current/dsl/org.gradle.api.plugins.ExtraPropertiesExtension.html for information on the replacement for dynamic properties.
Deprecated dynamic property: "props" on "root project 'private'", value: "true".
It can be fixed by replacing:
project.setProperty('props', props)
with
project.ext.props = props
Just to supplement the response given by #Steinar:
it's still possible to use next syntax:
project.ext.set('prop_name', prop_value)
in case you have several properties from file:
props.each({ project.ext.set(it.key, it.value)} )