Run scala app with maven dependencies plus some java code - java

I have created a Scala application. This application has some maven dependencies. But this application has also some java code. Scala code is under
src/main/scala/...
and the java code is under
src/main/java/...
which I use through scala. The main class is a scala object (not java). I compile the application successfully via IntelliJ. When I try to run the application using:
scala -J-Xmx4g MyApp.jar
I get the following exception:
java.lang.NullPointerException
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at scala.reflect.internal.util.ScalaClassLoader$$anonfun$tryClass$1.apply(ScalaClassLoader.scala:43)
at scala.reflect.internal.util.ScalaClassLoader$$anonfun$tryClass$1.apply(ScalaClassLoader.scala:43)
at scala.util.control.Exception$Catch$$anonfun$opt$1.apply(Exception.scala:119)
at scala.util.control.Exception$Catch$$anonfun$opt$1.apply(Exception.scala:119)
at scala.util.control.Exception$Catch.apply(Exception.scala:103)
at scala.util.control.Exception$Catch.opt(Exception.scala:119)
at scala.reflect.internal.util.ScalaClassLoader$class.tryClass(ScalaClassLoader.scala:42)
at scala.reflect.internal.util.ScalaClassLoader$class.tryToInitializeClass(ScalaClassLoader.scala:39)
at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.tryToInitializeClass(ScalaClassLoader.scala:101)
at scala.reflect.internal.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:63)
at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:101)
at scala.tools.nsc.CommonRunner$class.run(ObjectRunner.scala:22)
at scala.tools.nsc.JarRunner$.run(MainGenericRunner.scala:13)
at scala.tools.nsc.CommonRunner$class.runAndCatch(ObjectRunner.scala:29)
at scala.tools.nsc.JarRunner$.runJar(MainGenericRunner.scala:25)
at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:69)
at scala.tools.nsc.MainGenericRunner.run$1(MainGenericRunner.scala:87)
at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:98)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:103)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
Note that I can run the application from the IDE. Also note that I have added some maven plugins as suggested from other websites with similar exceptions. The plugins are:
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<executions>
<execution>
<id>scala-compile-first</id>
<phase>process-resources</phase>
<goals>
<goal>add-source</goal>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
What is the reason of the exception?

The answer to my question was quite simple. The folder scala had to be marked as "Sources Root" and the folder java had to be marked as "Generated Sources Root" from IntelliJ.
The application now works as expected.

Related

What is the difference between maven compiler plugin and maven toolchains plugin?

I had to integrate some legacy code into my maven build, so I used the maven-recommended toolchains plugin to change the java version:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-toolchains-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<goals>
<goal>toolchain</goal>
</goals>
</execution>
</executions>
<configuration>
<toolchains>
<jdk>
<version>1.5</version>
</jdk>
</toolchains>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.0</version>
<configuration>
<compilerArgs>
<arg>-Xmaxerrs</arg>
<arg>1000</arg>
</compilerArgs>
</configuration>
</plugin>
Then I ran into the max 100 compile errors problem which required passing special options to javac and found I was able to do it just with maven compiler:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.0</version>
<configuration>
<fork>true</fork>
<compilerVersion>1.5</compilerVersion>
<executable>C:\Java\jdk-1.5.0_22\bin\javac.exe</executable>
<source>1.5</source>
<target>1.5</target>
<compilerArgs>
<arg>-Xmaxerrs</arg>
<arg>1000</arg>
</compilerArgs>
</configuration>
</plugin>
Both snippets produce the same result: the java compiler is changed from the maven default to java 1.5. Both run in about the same amount of time, so there's no visible performance difference. I'd like to know if there are any benefits of one over the other so I know when to use each.
They do different things:
The compiler plugin specifically configures how your Java code is compiled (and only that).
The toolchains plugin just ensures that other plugins are all using the same Java tool chain (i.e. the same JDK) to compile, run, test, generate javadocs and so on.
This is explained in the respective plugins' documentation.
Note that not all plugins are "tool chain aware", but the compiler plugin is.
... are any benefits of one over the other
Well there there are things you can do with one and not the other and vice versa. For example, you can't set Java compiler options using the toolchain plugin.
However, they are not mutually exclusive. You can use both in the same POM file.

ClassNotFoundException in cucumber framework

I am using Cucumber framework for mobile app testing. In pom.xml, I have given this below plugin to run TestClass.java - which has code for uploading the latest APK version of the app. Main method is present inside this TestClass. I need this to run before the actual test execution. So I have used exec plugin. I'm getting this error if I am running with pom.xml --> mvn clean test. ClassNotFoundExpection is always thrown with pom.xml, but the individual class runs perfectly.
pom.xml:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>installAPK</id>
<phase>generate-test-sources</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<includePluginDependencies>true</includePluginDependencies>
<mainClass>org.com.package1.TestClass</mainClass>
</configuration>
</plugin>
Console error:
java.lang.ClassNotFoundException: org.com.package1.TestClass
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:246)
at java.lang.Thread.run(Thread.java:748)
I also tried changing the phase after test-compile. Still i am getting the same error. Someone pls help.
According to the exec-maven-plugin documentation, the default dependency scope for the execution is runtime. Please change it to test with the following configuration if the TestClass is part of the test sources.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
...
</executions>
<configuration>
...
<classpathScope>test</classpathScope>
</configuration>
</plugin>

Gradle - Is there a possibility to compile a single Java class before the rest of the project?

I am migrating my project from Maven to Gradle and i have a Java Class that i need to have compiled before the rest of the project. This class creates a file that will be used by the project.
Does anyone have an idea how to accomplish this task? Thanks
Edit:
The following is the Maven solution:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>11</release>
</configuration>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<compilerArgument>-proc:none</compilerArgument>
<includes>
<include>PATH/TO/CLASS/AnnotationProcessor.java</include>
</includes>
</configuration>
</execution>
<execution>
<id>compile-project</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
The AnnotationProcessor scrapes and stores all annotation data that the project declares. This class is supposed to be compiled before the rest of the project. At least that is what the comment section says.
Seems like you have some class that needs to exist before the rest of the project can be built. One way to resolve this would be to extract the dependency to a separate module so you have a multiproject build... This post may help you achieve what you want.
Build order of Maven multimodule project?
You can also introduce custom tasks in Gradle that will enable you to have "dependsOn(someTask)"
See https://docs.gradle.org/current/userguide/tutorial_using_tasks.html#sec:task_dependencies for more/examples

Junit 5 #SpringBootTest executable jar

I am trying to create an executable jar with my test. I cannot use maven to run the tests so I am trying to create a jer that will execute them.
I have a jar with all the test's and with all dependencies. But, when I try to run:
java -jar target/tests-0.0.1-SNAPSHOT-spring-boot.jar
I am getting -
Exception in thread "main" java.lang.ClassNotFoundException: com.xxx.xx.tests.framework.SDAutomation
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:93)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
pom.xml include the following to create the jar:
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>spring-boot</classifier>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals> <goal>single</goal> </goals>
<configuration>
<archive>
<manifest>
<mainClass>com.xxx.xx.tests.framework.SDAutomation</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
Any help will be great.
Edit 1:
found a seleution by creating a main with LauncherFactory
for example:
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
.selectors(
selectClass(SDAutomation.class)
)
.build();
Launcher launcher = LauncherFactory.create();
// Register a listener of your choice
SummaryGeneratingListener listener = new SummaryGeneratingListener();
launcher.registerTestExecutionListeners(listener);
launcher.execute(request);
TestExecutionSummary summary = listener.getSummary();
taken from juint doc
Spring boot works with a Jar which is not a Jar really. When you use spring-boot-maven- plugin - you instruct maven to prepare such a spring boot jar. I suggest to open this jar with some kind of WinRar/WinZip application and see what's inside actually.
So, if you have a spring boot jar and try to run it as a spring boot application it will load the main class and run it.
This main class should run programmatically all the automation tests and If I understand correctly this is exactly what SDAutomation is supposed to do.
But then you use maven assembly plugin and try to edit its manifest and specify the main plugin - do not do it. Instead specify the main class in a spring boot plugin. So this is clearly a mistake
The third step is even more confusing - you create a test jar, that's cool, but where do you use it?
So how to really solve this issue:
You should decide whether you want to use spring boot at all to run tests. Frankly I don't see a point of doing so - you could create a fat jar of all the dependencies and run tests from there. Unless these tests are not designed as #SpringBootTest which is also doesn't make sense for automation tests, here is why:
Spring Boot Test is an integration framework as opposed to automation tests which are usually cover the end to end flow. Automation tests run in the different JVM as the application as opposed to spring boot tests that provide a lot of convenience features for loading the application context of the real application inside of the test (or a part of application context). Automation tests should not load any production code at all... Probably if you could elaborate more on the purpose of the automation test suite - I could provide more information.
Even if you run the spring boot application, it should not be the same spring boot application that runs the production code. Probably you should create another maven module, provide a dependency on the artifact with a test classifier and in the main method use console application (again, no web server in this case is required) to run the test suite.
Last but not the least. Surefire/failsafe plugins of maven besides actually running the tests, also produce reports that can be integrated with a CI tool. Since you won't have any maven / surefire there (from your comment) you won't be able to benefit from these reports.
Below are steps ->
Step 1: Add the below plugins to your POM file -
<build>
<finalName>dockerized-springfield</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/libs
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/java/com/automation/framework/gui/testng.xml</suiteXmlFile>
</suiteXmlFiles>
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
</argLine>
<classpathDependencyExcludes>
<classpathDependencyExclude>com.vaadin.external.google:android-json</classpathDependencyExclude>
</classpathDependencyExcludes>
</configuration>
</plugin>
</plugins>
</build>
Step 2: Run mvn commands to create jars
mvn package -DskipTests
This will create 3 jars files inside your target folder
application.jar [Springboot jar which contains code inside "main" folders along with the dependencies.]
application.jar.original [Jar which ONLY contains code inside "main" folders]
application-tests.jar [Jar which contains code inside the "test" folder.]
We only need the 2nd and 3rd jar files. You may delete the first file.
Now rename the second file and remove the ".original" from its file name. Let's say mainapplication.jar
We will also need the libs folder which contains jar files for respective dependencies mentioned in the POM file.
Step 3: Run your jar files.
java -cp mainapplication.jar:application-tests.jar:libs/* org.testng.TestNG testng.xml

GWT SuperDevMode fails to see changes

I'm trying to setup my project to use gwt maven plugin. Its compiling properly but I'm not able to use either the dev mode or super dev mode for development.
My settings are as follows:
Maven configurations in order
mvn clean install
mvn tomcat7:run-war-only
mvn gwt:run-codeserver
GWT Version: 2.6.1
IDE: Intellij 14 Community Edition
When I make changes to client java files and click the "compile" button on the code server page, they're not reflected on the webpage. I suspect the code server is not looking at the same sources I'm changing. Specifically i think its looking for sources to compile in target/{project-name}/*
Following is the snippet of the POM file I'm using.
<sourceDirectory>src/main/java</sourceDirectory>
<resources>
<resource>
<directory>src/main/java</directory>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<outputDirectory>${project.build.directory}/${project.artifactId}-${project.version}/WEB-INF/classes</outputDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<!--compilerArgument>-proc:none</compilerArgument-->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.0</version>
<configuration>
<path>${tomcat.context}</path>
<port>${tomcat.webport}</port>
<ajpPort>${tomcat.ajpport}</ajpPort>
<contextReloadable>true</contextReloadable>
</configuration>
</plugin>
<!-- GWT Maven Plugin -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>${maven.gwt.plugin.version}</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<configuration>
<draftCompile>true</draftCompile>
<hostedWebapp>${webappDirectory}</hostedWebapp>
<noServer>true</noServer>
<port>${tomcat.webport}</port>
<runTarget>${tomcat.context}/index.html</runTarget>
<!--codeServerWorkDir>${webappDirectory}</codeServerWorkDir-->
<copyWebapp>true</copyWebapp>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>exploded</goal>
</goals>
</execution>
</executions>
<configuration>
<webappDirectory>${webappDirectory}</webappDirectory>
</configuration>
</plugin>
</plugins>
</build>
Any help would be appreciated!!
Because you list src/main/java as a <resource>, its files are copied to the ${project.build.outputDirectory}, and that one comes first in the classpath because you could filter files from <resource> and have <source> and <resource> intersect (which is the case here). See http://jira.codehaus.org/browse/MGWT-290
So either:
remove src/main/java from project resources
remove *.java files from project resources (so at least they're not copied over to the output directory and don't shadow src/main/java)
or run mvn resources:resources each time you change files in src/main/java (like you have to do with files in src/main/resources, because of possible filtering); this can be automated by your IDE or some other tool (e.g. watchman) though.
I would upgrade the project to use gwt-2.7.0 and gwt-maven-2.7.0, then nothing special is needed to run superdev mode among your app in a servlet container, just run mvn gwt:run and point your browser to http://localhost:8888, then each time you change your code just hit refresh in your browser to recompile the app.
As you can see it's pretty simpler, and you would take advance of recompiling in 2.7.0 is a lot faster.
Having tried all possible forums' advice and diverse codeServer launch parameters unsuccessfully, the only means I have found to trigger a refresh without restarting any server is to click again on the bookmark 'Dev Mode Off' followed by 'Dev Mode On' then 'Compile'button ... and the code Server recompiles the changed java source incrementally! (the Dev Mode shortcuts are those you should have dragged from the code server home page like http://localhost:9876 into the browser bookmarks).
A page refresh was enough with "Google Plugin for Eclipse" ( ==GPE, deprecated Jan2018) and -as it seems- no longer with "GWT Eclipse Plugin" (replacing GPE) (appreciate the subtle difference in wordings!)

Categories

Resources