Setting descriptions for mojos and parameters in maven plugin - maven

I am writing a maven plugin and I would like to add some documentation for the available goals and parameters.
When I run mvn help:describe -Dplugin=myplugin -Ddetail it prints out available goals and parameters. However it lists (no description) everywhere. From searching the internet I could not figure out where such a description is to be set.
For reference, my plugin is written in scala and looks roughly like this.
import org.apache.maven.plugins.annotations.{ Component, Parameter }
class MyMojo extends AbstractMojo {
#Parameter(defaultValue = "false", readonly = false)
private var skipFormatting: Boolean = _
}
So my question would be: where can set a description, such that it will show up with mvn help:describe -Dplugin=myplugin?

I strongly recommend to use the following:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<id>default-descriptor</id>
<phase>process-classes</phase>
</execution>
<execution>
<id>generate-helpmojo</id>
<goals>
<goal>helpmojo</goal>
</goals>
</execution>
</executions>
</plugin>
which will generate the help part during the build process. And yes you have to add some javadoc like this:
#Mojo(name = "failure", defaultPhase = LifecyclePhase.NONE,
requiresDependencyResolution = ResolutionScope.NONE, threadSafe = true)
public class FailureMojo extends AbstractMojo {
I don't understand why you haven't have any annotations on your Mojo?
The documentation like this: https://maven.apache.org/plugins/maven-install-plugin/plugin-info.html will be generated from the javadoc on parameters etc. https://github.com/apache/maven-install-plugin/blob/master/src/main/java/org/apache/maven/plugins/install/InstallMojo.java#L69

Based on examples when running the help:describe on familiar plugins like the maven-jar-plugin, tt appears it's based on the Javadoc of the Mojo class.

Related

OpenAPI Codegen "oneOf": Java classes not generated correctly

TLDR:
OpenAPI offers 'oneOf' property. The resulting java classes created do not seem to allow one of the possible instances.
Details:
I am creating the spring/java server side rest api code using OpenAPI maven plugin.
The request class is not such that the passed object is not parsed correctly. The following error is printed in the console.
JSON parse error: Could not resolve subtype of [simple type, class com.model.Issuer]: missing type id property 'type' (for POJO property 'issuer'); nested exception is com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve subtype of [simple type, class com.Issuer]: missing type id property 'type' (for POJO property 'issuer')\n at [Source: (PushbackInputStream); line: 3, column: 15] (through reference chain: com.IssueCredentialRequest[\"credential\"]->com.Credential[\"issuer\"])
The reason seem to be that the generated class does not have subtypes list in the annotation:
package com.sphereon.vdp.vc.service.model;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
#JsonSubTypes({
})
public interface OneOfIssuer {
}
There is another class which is generated correctly. The reason that this one is generated correctly is probably that this one deals with non-primitive types.
package com.sphereon.vdp.vc.service.model;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(value = VerifyPresentationRequest.class, name = "VerifyPresentationRequest"),
#JsonSubTypes.Type(value = ProoflessVerifyPresentationRequest.class, name = "ProoflessVerifyPresentationRequest")
})
public interface OneOfpresentationsVerifyBody {
}
Can someone point to how to fix the code generation for primitive types?
<plugin>
<groupId>io.swagger.codegen.v3</groupId>
<artifactId>swagger-codegen-maven-plugin</artifactId>
<version>3.0.33</version>
<dependencies>
<dependency>
<groupId>com.github.jknack</groupId>
<artifactId>handlebars</artifactId>
<version>4.3.0</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>vc-rest-api-issuer-source-generation</id>
<goals>
<goal>generate</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<inputSpec>${pom.basedir}/specifications/issuer.yml</inputSpec>
<language>spring</language>
<apiPackage>com.company.vdp.vc.service.api</apiPackage>
<modelPackage>com.company.vdp.vc.service.model</modelPackage>
<artifactVersion>${project.version}</artifactVersion>
<generateModels>true</generateModels>
<generateApis>true</generateApis>
<generateModelDocumentation>true</generateModelDocumentation>
<generateSupportingFiles>true</generateSupportingFiles>
<verbose>${openapi-codegen-verbose}</verbose>
<output>${project.basedir}/target/generated-sources/java/api</output>
<ignoreFileOverride>${project.basedir}/target/generated-sources/java/api/.swagger-codegen-ignore</ignoreFileOverride>
<configOptions>
<delegatePattern>true</delegatePattern>
<dateLibrary>java8</dateLibrary>
<useTags>true</useTags>
</configOptions>
</configuration>
</execution>
<execution>
<id>vc-rest-api-verifier-source-generation</id>
<goals>
<goal>generate</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<inputSpec>${pom.basedir}/specifications/verifier.yml</inputSpec>
<language>spring</language>
<apiPackage>com.company.vdp.vc.service.api</apiPackage>
<modelPackage>com.company.vdp.vc.service.model</modelPackage>
<artifactVersion>${project.version}</artifactVersion>
<generateModels>true</generateModels>
<generateApis>true</generateApis>
<generateModelDocumentation>true</generateModelDocumentation>
<generateSupportingFiles>true</generateSupportingFiles>
<verbose>${openapi-codegen-verbose}</verbose>
<output>${project.basedir}/target/generated-sources/java/api</output>
<ignoreFileOverride>${project.basedir}/target/generated-sources/java/api/.swagger-codegen-ignore</ignoreFileOverride>
<configOptions>
<delegatePattern>true</delegatePattern>
<dateLibrary>java8</dateLibrary>
<useTags>true</useTags>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
Following is the spec file that I am using without editing.
https://github.com/w3c-ccg/vc-api/blob/main/components/Issuer.yml
https://github.com/w3c-ccg/vc-api/blob/main/verifier.yml

Unsatisfied dependency expressed through field 'buildProperties'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException

<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>build-info</id>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
this the main class
public class GetSpaOsmiumVersionClient implements CommandLineRunner{
#Autowired
BuildProperties buildProperties;
public static void main( String[] args ){
SpringApplication app = new SpringApplication(GetSpaOsmiumVersionClient.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
}
#Override
public void run(String... args) throws Exception {
Options options = new Options();
options.addOption("h", "help", false, "prints the help content");
options.addOption("v", "version", false, "version spa osmium");
try{
//Etape 2: Analyse de la ligne de commande
CommandLineParser parser = new DefaultParser();
CommandLine commandLine = parser.parse(options, args);
if(commandLine.hasOption("v")){
buildProperties.getVersion();
}else {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp( "App" , options );
System.exit(1);
}
Found this question in Google Search for a similar issue, so I'll leave this answer so other fellow developers can save some time.
The error message in the question title
Unsatisfied dependency expressed through field 'buildProperties'
is often caused by a misunderstanding on how the property BuildProperties works.
Basically, BuildProperties only works if we have executed the 'build-info' goal of Maven Spring Boot Plugin (aka, run the following command in cmd):
mvn spring-boot:build-info
The reason is that BuildProperties is NOT something built-in, but a product of that Maven goal. When that goal is executed, a file build-info.properties is generated - and the code will read from that file.
Usually Maven project is set up so that it will automatically execute that goal on pipeline (in plugins part, see picture below). However when we trigger a run on local IDE, that goal isn't automatically executed, hence the problem.
Detailed explanation on how it works can be found in this reference:
https://www.vojtechruzicka.com/spring-boot-version/
If you prefer to work with IDE (eg: IntelliJ) instead of command line, you might find Maven tool window. Your job is to "run" the "build-info" goal before starting the server.
Example for IntelliJ: https://www.jetbrains.com/help/idea/work-with-maven-goals.html

Updating Apache Felix SCR to OSGi Declarative Services R6 - #Property

I'm updating from Apache Felix SCR Annotations to OSGi DS R6 ones and the one is causing me more problem is the #Property inside the class.
Before I had:
#Component (immediate = true)
#Service (A.class)
public class AImpl implements A
{
#Property (intValue = 604800)
public static final String A = "a";
...
}
Now I have:
#Component (service = A.class, immediate = true)
#Designate (ocd = Configuration.class)
public class AImpl implements A
{
...
}
and
#ObjectClassDefinition (name = "Bla")
public #interface Configuration
{
#AttributeDefinition (name = "A", type = AttributeType.INTEGER)
int A() default 604800;
}
The most bizarre thing on all of this is:
Before, I could see my AImpl class as a component.
Now, I couldn't see my AImpl class as a component and everyone who uses it cannot start because of unsatisfied references.
How come changing just configurations like this can cause this behaviour ? Maybe I'm missing something ?
The stranger part on all of this is my xml is inside the .jar and seems ok.
The scr:info is getting me nullpointer exception and I cannot see my component, meaning the scr:list will no help in anything.
XML BELLOW:
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.3.0" name="AImpl" immediate="true" activate="init" deactivate="stop">
<implementation class="AImpl"/>
<service>
<provide interface="A"/>
</service>
<reference name="Bla1" interface="Bla1Service" bind="bindBla1Service" unbind="unbindBla1Service"/>
<property name="PROP.EVENT.INTERVAL" type="Long" value="900000"/>
</scr:component>
Ps.: The classes are with strange names and so on because it's from a private company.
STACKTRACE:
2017-12-11T16:40:27.689+0100 [Framework Event Dispatcher] ERROR o.o.p.l.l.internal.FrameworkHandler:144 frameworkEvent FrameworkEvent ERROR - org.apache.felix.scr
org.osgi.framework.BundleException: The activator org.apache.felix.scr.impl.Activator for bundle org.apache.felix.scr is invalid
at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadBundleActivator(AbstractBundle.java:172)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:679)
at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:381)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.updateWorker(AbstractBundle.java:645)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.update(AbstractBundle.java:592)
at org.apache.felix.webconsole.internal.core.UpdateHelper.doRun(UpdateHelper.java:60)
at org.apache.felix.webconsole.internal.core.BaseUpdateInstallHelper.doRun(BaseUpdateInstallHelper.java:93)
at org.apache.felix.webconsole.internal.core.UpdateHelper.doRun(UpdateHelper.java:70)
at org.apache.felix.webconsole.internal.core.BaseUpdateInstallHelper.run(BaseUpdateInstallHelper.java:123)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.ClassCastException: org.apache.felix.scr.impl.Activator cannot be cast to org.osgi.framework.BundleActivator
at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadBundleActivator(AbstractBundle.java:167)
... 9 common frames omitted
Part of POM.XML who install on karaf my bundles:
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-kar-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<inherited>false</inherited>
<configuration>
<includeScope>runtime</includeScope>
<prependGroupId>true</prependGroupId>
<excludeTransitive>true</excludeTransitive>
<artifactItems>
<artifactItem>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.framework</artifactId>
<version>${org.osgi.framework.version}</version>
</artifactItem>
<artifactItem>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>${org.osgi.core.version}</version>
</artifactItem>
<artifactItem>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr</artifactId>
<version>${org.apache.felix.scr.version}</version>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
This part looks like the error: service=AImpl.class. Your component should be published as a service using its interface A, not the implementation class.
This normally happens implicitly because the component directly implements interface A, but you have overridden that.
The solution should be to simply delete the service=AImpl.class attribute from the #Component annotation.
Your AImpl class still being a Component. However, now it's a "Configuration" Component, hence it has a #Designate annotation linking to a #ObjectClassDefinition Property class.
Go to the Configuration tab and you should see your Component and its properties.

Generate DDL script at MAVEN build with Hibernate4 / JPA 2.1

It seems like the hibernate3-maven-plugin used to generate DDL create/drop scripts is not compatible any more with Hibernate 4.3 and newer versions (using JPA 2.1).
I use this plugin configuration :
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>hibernate3-maven-plugin</artifactId>
<version>3.0</version>
<executions>
<execution>
<id>generate-sql-schema</id>
<phase>process-sources</phase>
<goals>
<goal>hbm2ddl</goal>
</goals>
<configuration>
<hibernatetool>
<jpaconfiguration persistenceunit="${persistenceUnitName}" />
<hbm2ddl update="true" create="true" export="false"
outputfilename="src/main/sql/schema.sql" format="true"
console="true" />
</hibernatetool>
</configuration>
</execution>
</executions>
</plugin>
But I get the following error :
[ERROR] Failed to execute goal org.codehaus.mojo:hibernate3-maven-plugin:3.0:hbm2ddl (generate-sql-schema) on project my-project: There was an error creating the AntRun task.
An Ant BuildException has occured: java.lang.NoClassDefFoundError: org/hibernate/util/ReflectHelper: org.hibernate.util.ReflectHelper -> [Help 1]
This class as migrated to a new package : org.hibernate.internal.util.ReflectHelper
However i found no clear way to keep generating DDL create scripts at MAVEN build.
There is no hibernate4-maven-plugin, or any other official way to do it.
So what ? Isn't it a main feature that should be supported ? How to do it ?
As Hibernate 4.3+ now implements JPA 2.1 the appropriate way to generate DDL scripts is to use following set of JPA 2.1 properties :
<property name="javax.persistence.schema-generation.scripts.action" value="create"/>
<property name="javax.persistence.schema-generation.create-source" value="metadata"/>
<property name="javax.persistence.schema-generation.scripts.create-target" value="target/jpa/sql/create-schema.sql"/>
A nice summary of others properties and context of schema generation in JPA 2.1 can be found here :
https://blogs.oracle.com/arungupta/entry/jpa_2_1_schema_generation
And official JPA 2.1 specifications here :
https://jcp.org/aboutJava/communityprocess/final/jsr338/index.html
As this will be generated at runtime, you may want to execute this DDL generation at build.
Here is the JPA 2.1 approach to generate this script programmatically :
import java.io.IOException;
import java.util.Properties;
import javax.persistence.Persistence;
import org.hibernate.jpa.AvailableSettings;
public class JpaSchemaExport {
public static void main(String[] args) throws IOException {
execute(args[0], args[1]);
System.exit(0);
}
public static void execute(String persistenceUnitName, String destination) {
System.out.println("Generating DDL create script to : " + destination);
final Properties persistenceProperties = new Properties();
// XXX force persistence properties : remove database target
persistenceProperties.setProperty(org.hibernate.cfg.AvailableSettings.HBM2DDL_AUTO, "");
persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_DATABASE_ACTION, "none");
// XXX force persistence properties : define create script target from metadata to destination
// persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_CREATE_SCHEMAS, "true");
persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_SCRIPTS_ACTION, "create");
persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_CREATE_SOURCE, "metadata");
persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_SCRIPTS_CREATE_TARGET, destination);
Persistence.generateSchema(persistenceUnitName, persistenceProperties);
}
}
As you can see it's very simple !
Now you can use this in an AntTask, or MAVEN build like this (for MAVEN) :
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>generate-ddl-create</id>
<phase>process-classes</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<!-- ANT Task definition -->
<java classname="com.orange.tools.jpa.JpaSchemaExport"
fork="true" failonerror="true">
<arg value="${persistenceUnitName}" />
<arg value="target/jpa/sql/schema-create.sql" />
<!-- reference to the passed-in classpath reference -->
<classpath refid="maven.compile.classpath" />
</java>
</target>
</configuration>
</execution>
</executions>
</plugin>
Note that the official hibernate-maven-plugin also may, or may not, do the trick in some way :
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-maven-plugin</artifactId>
<version>4.3.1.Final</version>
</dependency>
Enjoy ! :)

Annotation scan not scanning external jars in classpath

Issue: Spring Component Annotation scan not picking up the class annotated in the external jar which is not included in pom.xml. But i need to scan for classes with specific annotation from external jars. These external jars will be placed in the classpath but will not be known to my application during compile time.
1) We have a maven module(artifactId="metric_processor") which produces a jar file(metric_processor.jar) and has following classes
package com.metric;
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface ProcessMetric {
String name();
}
package com.metric;
public interface MetricProcessor {
int computeMetric();
}
package com.metric;
#ProcessMetric(name="LATENCY")
#Component
public class LatencyMetricProcessor implements MetricProcessor {
.....
}
2) We have another maven module ("artifactId="metric_processor_external") which produces a jar(metric_processor_external.jar) and includes "metric_processor" module as compile time scope.
package com.metric;
#ProcessMetric(name="TEST_METRIC_EXTERNAL")
#Component
public class TestMetricProcessor implements MetricProcessor {
....
}
3) We have a third(main) maven module(artifactId="main_application") which is a stand alone application(uses spring) which includes module "metric_processor" in compile scope. (But does not include "metric_processor_external"). The build plugin for the third module is
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.main.TriggerMetricProcessor</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Application context xml for this module is
<beans>
<context:component-scan base-package="com.metric">
<context:include-filter type="annotation" expression="com.metric.ProcessMetric" />
</context:component-scan>
<bean id="triggerMetricProcessor" class="com.main.TriggerMetricProcessor" />
</beans>
I have the following class which is the starting point of the application
package com.main;
import ...
public class TriggerMetricProcessor {
public static void main(String[] args) throws Exception {
ApplicationContext context =
new ClassPathXmlApplicationContext("application-context.xml");
TriggerMetricProcessor triggerMetricProcessor = (TriggerMetricProcessor) context.getBean("triggerMetricProcessor");
triggerMetricProcessor.initMetricProcessor(context);
}
private void initMetricProcessor(ApplicationContext context) {
GenericBeanFactoryAccessor beanFactoryAccessor = new GenericBeanFactoryAccessor(context);
final Map<String, Object> metricProcessors = beanFactoryAccessor.getBeansWithAnnotation(ProcessMetric.class);
for (final Object metricProcessor : metricProcessors.values()) {
final Class<? extends MetricProcessor> metricProcessorClass = (Class<? extends MetricProcessor>)metricProcessor.getClass();
final ProcessMetric annotation = metricProcessorClass.getAnnotation(ProcessMetric.class);
System.out.println("Found MetricProcessor class: " + metricProcessorClass + ", with name: " + annotation.name());
}
}
}
we compile the third module as
maven clean install assembly:single
This produces the jar file "main_application-with-dependencies.jar"
Then we run its as
java -cp "metric_process_external.jar" -jar main_application-with-dependencies.jar
Now the application finds only "LatencyMetricProcessor" and does not find the "TestMetricProcessor".
Can someone please help?
When you use the -jar option to execute a jar file, the -cp option is ignored.
The Oracle Java docs for the -jar option say:
-jar
Execute a program encapsulated in a JAR file. The first argument is
the name of a JAR file instead of a startup class name. In order for
this option to work, the manifest of the JAR file must contain a line
of the form Main-Class: classname. Here, classname identifies the
class having the public static void main(String[] args) method that
serves as your application's starting point. See the Jar tool
reference page and the Jar trail of the Java Tutorial for information
about working with Jar files and Jar-file manifests.
When you use this option, the JAR file is the source of all user
classes, and other user class path settings are ignored.
Also check out this post: stackoverflow.com/questions/5879925/in-linux-how-to-execute-java-jar-file-with-external-jar-files
So you'll need to specify the metric_process_external.jar in your manifest file using a Class-Path: header. You should be able to get your Maven assembly plugin to do that.
If that's not practical, you'll need to run your application without the -jar flag:
java -cp "metric_process_external.jar:main_application-with-dependencies.jar" com.main.TriggerMetricProcessor

Resources