Maven exec plugin Class Not Found Exception - maven

when I right click on the class that has the main() method in Eclipse, and go into properties -> resource, the path to the class is this:
/UserRegistrationServices/src/main/java/main/Application.java
In my POM.xml file I have this:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>my-execution</id>
<phase>package</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>UserRegistrationServices.src.main.java.main.Application.java</mainClass>
</configuration>
</plugin>
But for some reason maven cannot find the class.
Help would be appreciated, thanks.

The <mainClass> element takes a fully qualified class name. The fully qualified name of a class consists of the package and the actual name of class. In a default Maven project, the package name is relative to src/main/java. That means, the package of your Application class is main. You can verify that by looking at the package declaration in the class itself.
Therefore the <mainClass> value needs to be main.Application.

Related

Mapstruct - cannot find symbol [Kotlin + Maven]

I'm having the following error when I run the command mvn clean install:
[ERROR] /Users/xxx/xxx/xxx/xxx.xxx/target/generated-sources/kapt/compile/com/xxx/xxx/xxx/xxx/DataMapperImpl.java:[10,40] cannot find symbol
[ERROR] symbol: class DataMapperDecorator
[ERROR] /Users/xxx/xxx/xxx/xxx.xxx/target/generated-sources/kapt/compile/com/xxx/xxx/xxx/xxx/DataMapperImpl.java:[10,74] cannot find symbol
[ERROR] symbol: class DataMapper
[ERROR] /Users/xxx/xxx/xxx/xxx.xxx/xxx/generated-sources/kapt/compile/com/xxx/xxx/xxx/api/DataMapperImpl.java:[12,19] cannot find symbol
[ERROR] symbol: class DataMapper
[ERROR] location: class com.xxx.xxx.xxx.xxx.DataMapperImpl
It seems that after mapstruct has generated the DataMapperImpl.java class it is not able to find the classes DataMapper and DataMapperDecoretor.
The code related to mapstruct is in a xxx.kt file:
//Other stuff
...
#Mapper
#DecoratedWith(DataMapperDecorator::class)
interface DataMapper {
#Mappings(
Mapping(source = "data.value", target = "dataValue"),
Mapping(source = "data.current.value", target = "currentValue"),
)
fun toDto(data: Data) : RefDataDto
}
abstract class DataMapperDecorator : DataMapper {
#Autowired
private val delegate: DataMapper? = null
override fun toDto(data: Data): dataDto {
val dataDto = delegate!!.toDto(data)
dataDto.primaryValue = data.primaryValue?.let { CurrencyUtil.toMajor(it) }
return dataDto
}
}
Regarding the pom files I have in the root file:
...
<properties>
...
<org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
</properties>
...
and this is the pom of the module where I'm using mapstruct:
...
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/main/kotlin</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
<execution>
<id>kapt</id>
<goals>
<goal>kapt</goal>
</goals>
<configuration>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
...
I hid some part of the files with dots and I'm not using the project Lombok (I saw same problems related with it we you are trying to use these projects together).
UPDATE 1:
I noticed that the error is related to the fact that from the generated class DataMapperImpl.java the package where there are the classes that this generated class should use is not visible. Indeed I see this error:
[ERROR] /Users/xxx/xxx/xxx/xxx.xxx/xxx/generated-sources/kapt/compile/com/xxx/xxx/xxx/xxx/RefDataMapperImpl.java:[3,47] package com.my.package.application.domain does not exist
and of course this package exist!
UPDATE 2:
I'm continuing to investigate on this issue. I tried to make it simpler deleting the DataMapperDecorator and put the DataMapper, the Data and the DataDto class in the same file. Still the same error cannot find symbol: class for all the three classes. I'm not sure if this is related to the fact that in the DataMapperImpl (the generated class) doesn't have the import of these classes. There are imports just for the standard java libraries such as:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID;
import javax.annotation.processing.Generated;
EDIT 1:
From the log I can also see the following warning:
[WARNING] 'tools.jar' was not found, kapt may work unreliably
UPDATE 3:
Without mapstruct under target->classes (using IntelliJ IDEA) I can see the classes of my project. On the other hand when I have introduced mapstruct what I'm seeing is that the mapstruct classes are generated under target->generated-sources->kapt->compile but under target->classes I don't see the other classes. Could the mapstruct classes be generated earlier than the other classes of my project causing the compiler to not find the Data, DataDto classes?
SOLVED!
The problem was due to the order of the compilation. By default the java compiler is executed before the kotlin compiler. That why the code generated by mapstruct wasn't able to find the kotlin classes. So it is needed to compiler the koltin classes before and then the java classes.
"The idea is to disable default compile execution and introduce our own to get control over the order in which goals are executed, so that we could run kotlin compiler before java compiler."
https://discuss.kotlinlang.org/t/maven-compiler-plugin-question/5260/4
So the solution came introducing the maven plugin:
https://kotlinlang.org/docs/maven.html#compile-kotlin-and-java-sources
So I added this to my pom file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<!-- Replacing default-compile as it is treated specially by maven -->
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<!-- Replacing default-testCompile as it is treated specially by maven -->
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
<execution>
<id>java-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>java-test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
I am not sure how Kotlin works with multiple classes in one source file.
What I would suggest is that you use dedicated files for the decorator and the mapper. That way MapStruct will create the correct code.
MapStruct is a Java annotation processor, we do not know anything about the Kotlin structure. It seems like the packages returned by the java annotation processing API are not correct.
Addition to #SGiux answer. The order of plugins in pom also matters:
kotlin-maven-plugin
maven-compiler-plugin

Specifying Main class in pom.xml for spring boot projects in Kotlin

I have created a Spring Boot project using Kotlin. I would like to create a .jar file with all the dependencies so that I can run the application from the command line. The FQCN for the main class is: com.example.Application.kt. I have following configuration in my pom.xml:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.example.Application</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
The application fails to start complaining that the mainClass was not found. Here is the sample exception:
Exception in thread "main" java.lang.ClassNotFoundException: com.example.Application
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:93)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:46)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:51)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:52)
What am I missing?
I am just attempting to learn Kotlin myself, but I suspect you may need to append Kt to the end of your classname. For example:
<manifest>
<mainClass>com.example.ApplicationKt</mainClass>
</manifest>
Unrelated to Spring, I encountered this issue myself when attempting to build an executable JAR. If you unzip your JAR and look at the class files, I believe you will find an ApplicationKt.class.
If so, this is because you did not define the main function within a class. In this scenario, Kotlin generates a static method belonging to a <filename>Kt.class version of your file. According to this SO answer:
Unlike Java, Kotlin allows you to define functions that are not inside a class. But if you want Java to talk to Kotlin that becomes a problem. How to solve it? Convert those functions into static methods of a class named as the file with the "Kt" suffix
You can find more info about that in the documentation
Similar to other answers, I got this working with Spring Boot 2.4.2 and Maven
pom.xml
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>demoapi.DemoApiApplicationKt</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
DemoApiApplicationKt
package demoapi
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
#SpringBootApplication
class DemoApiApplication
fun main(args: Array<String>) {
runApplication<DemoApiApplication>(*args)
}
Most likely exactly as the exception states: you are missing a class Application inside the package com.example having a companion object with a main method.
package com.example
import org.springframework.boot.ApplicationArguments
import org.springframework.boot.ApplicationRunner
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.context.annotation.Configuration
#SpringBootApplication
#Configuration
open class Application : ApplicationRunner {
override fun run(args: ApplicationArguments) {
}
companion object {
#JvmStatic
fun main(args: Array<String>) {
SpringApplication.run(Application::class.java, *args)
}
}
}
Ran into the same error. In my case, I had the main application in a different path than src/main//kotlin. Specifying that exact path in the sourceDirectory tag under the build tag solved my issue. This being said, you also need to append Kt to make your application class ApplicationKt. Below is the structure of my pom.xml:
<build>
<sourceDirectory>${project.basedir}/src/generated-source/kotlin</sourceDirectory>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.example.ApplicationKt</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>

Binding a custom Maven plugin to a default phase

I have a custom Maven plugin that I'm trying to bind to the package phase by default. I've tried every combination of using the #Mojo annotation along with the #Execute annotation, but it doesn't seem to auto bind.
The only way I manage to get my plugin to work is by defining it like this:
#Mojo(name = "put")
public class SSHMojo extends AbstractMojo {
And then in my project using the plugin, defining an execution. I'd like to avoid having to add the <executions> every time I want to use my plugin.
<plugin>
<groupId>com.patrickgrimard</groupId>
<artifactId>ssh-maven-plugin</artifactId>
<version>1.0.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>put</goal>
</goals>
</execution>
</executions>
<configuration>
<serverId>devopsmtl</serverId>
<host>example.com</host>
<remoteDirectory>/srv/www</remoteDirectory>
</configuration>
</plugin>
My full plugin pom can be found at https://github.com/pgrimard/ssh-maven-plugin/blob/master/pom.xml
Hi simply use the following:
#Mojo( name = "put", defaultPhase = LifecyclePhase.PACKAGE )
Apart from that i would suggest to use a newer version of maven-plugin-api (3.0 at least)...
Use annotation attribute defaultPhase (like already mentioned by khmarbaise):
#Mojo(name = "put", defaultPhase = LifecyclePhase.PACKAGE)
public class SSHMojo extends AbstractMojo { ... }
In the pom.xml of the consuming Maven project you can leave away the reference to the phase after this:
<plugin>
<groupId>com.patrickgrimard</groupId>
<artifactId>ssh-maven-plugin</artifactId>
<version>1.0.2</version>
<executions>
<execution>
<!-- <phase>package</phase> --><!-- needed no longer -->
<goals>
<goal>put</goal>
</goals>
</execution>
</executions>
...

Setting properties in maven with gmaven

I am trying to overwrite the following property in maven using gmaven:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<executions>
<execution>
<id>setproperty</id>
<phase>validate</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
pom.properties['main.build.directory']=project.parent.build.directory.absolutePath.replace('\\','/');
</source>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
But I get this error:;
[ERROR] Failed to execute goal org.codehaus.gmaven:gmaven-plugin:1.5:execute (setproperty) on project my-project: startup failed, script139276
2592853.groovy: 1: expecting ''', found '<EOF>' # line 1, column 84.
[ERROR] 1 error
What is wrong with the above groovy snippet?
Value of a property which is set using gmavenplus-plugin displays correctly when accessed using the plugin. It will display correctly even if it is accessed using different instances of the same plugin.
Problem arises when value of a property which is already initialized outside the plugin is altered by the plugin and it is accessed outside the plugin. Now the value of the property is not the value as updated by plugin. The updated value is now scoped within the plugin. As a workaround to solve this issue if a property has to be updated by the plugin and is required to be accessed outside the scope of plugin: do not declare or initialize it, in case it needs to be then declare and initialize the property through the plugin.
I agree with #khmarbaise that this is a little weird to do, but if you must...I'm not sure offhand why it isn't working. That plugin isn't really maintained anymore. <shamelessPlug>I think this should work:
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<id>setproperty</id>
<phase>validate</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<scripts>
<script><![CDATA[project.properties['main.build.directory']=project.parent.build.directory.replace('\\','/')]]></script>
</scripts>
</configuration>
</execution>
</executions>
</plugin>
For more info on this mojo, check out http://groovy.github.io/GMavenPlus/execute-mojo.html.
</shamelessPlug>. However, be aware that I believe this will be scoped within the plugin.

What is the format for specifying a package in the Antlr4 maven plugin?

What is the format for specifying a package in the Antlr4 maven plugin antlr4-maven-plugin?
I feel like I should be able to do the following:
<plugin>
<groupId>com.tunnelvisionlabs</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>4.0</version>
<configuration>
<arguments>package my.package.name</arguments>
</configuration>
<executions>
<execution>
<goals>
<goal>antlr4</goal>
</goals>
</execution>
</executions>
</plugin>
but that results in the following error:
[ERROR] Failed to execute goal com.tunnelvisionlabs:antlr4-maven-plugin:4.0:antlr4 (default) on project my_project: Unable to parse configuration of mojo com.tunnelvisionlabs:antlr4-maven-plugin:4.0:antlr4 for parameter arguments: Cannot assign configuration entry 'arguments' with value 'package my.package.name' of type java.lang.String to property of type java.util.List -> [Help 1]
If I am you, I will make a maven project per package and try this
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>4.0</version>
<configuration>
<sourceDirectory>${basedir}/src</sourceDirectory>
</configuration>
<executions>
<execution>
<goals>
<goal>antlr4</goal>
</goals>
</execution>
</executions>
</plugin>
but usually, When I pass an argument in maven configuration, I do the following. but I am not sure of that syntax in antlr4
<plugin>
<groupId>com.tunnelvisionlabs</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>4.0</version>
<configuration>
<arguments>
<argument>-package</argument>
<argument>my.package.name</argument>
</arguments>
</configuration>
<executions>
<execution>
<goals>
<goal>antlr4</goal>
</goals>
</execution>
</executions>
</plugin>
Edit: Notice the - in front of package so the antlr-maven-plugin will recognize it as a parameter
The package is automatically determined based on the location of the file in your project, similar to the way the package is determined for Java files. The output is also placed in a location determined by the location of the source file. To change the package where the code is generated, you'll need to move the grammar file.
Other arguments can be specified like this:
<arguments>
<argument>arg1</argument>
<argument>arg2</argument>
</arguments>
Your configuration arguments syntax is wrong.
Please change the configuration of antlr4-maven-plugin from
<configuration>
<arguments>package my.package.name</arguments>
</configuration>
to:
<configuration>
<arguments>
<argument>-package</argument>
<argument>my.package.name</argument>
</arguments>
</configuration>
In order to add package information to the generated code you must add the following annotation to the g4 file:
#header {
package com.this.is.my.package;
}
I tried
#header {
package com.this.is.my.package;
}
but when you have imports it adds package line for each file imported and as a result compiler errors raised in generated file. You have to be careful to add #header so file with imported grammars had only one package line. I think it's a bug.
I have the Demo.g4 inside src/main/antlr4/de/schmitz.
Now the classes are generated to target/generated-sources/antlr4/de/schmitz.
The package is de.schmitz.
Everything is correct.
Now I want to change the package and folders of the generated classes (actually NOT moving my Demo.g4):
<arguments>
<argument>-package</argument>
<argument>my.package</argument>
</arguments>
The classes are generated to target/generated-sources/antlr4/de/schmitz.
The package is my.package.
This cannot be compiled, so it could be an error.
So I want to change the output directory:
<outputDirectory>${project.build.directory}/generated-sources/antlr4/my/package</outputDirectory>
Now it get's buggy.
The package is my.package.
But the folder is target/generated-sources/antlr4/my/package/de/schmitz.
So it's concatenated instead of overwritten.

Resources