I am new to spring and maven. I have a simple hello world project using Spring . The project builds successfully but i face the following error at runtime:
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/context/ApplicationContext
This is the main app: App.java
package com.test.SpringMaven2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
System.out.println( "Hello World!" );
ApplicationContext context = new AnnotationConfigApplicationContext(HelloWorldConfig.class);
HelloWorld hello = (HelloWorld) context.getBean("helloWorld");
hello.setName("Adnan");
hello.getName();
}
}
This is the HelloWorld bean
package com.test.SpringMaven2;
public class HelloWorld{
private String name;
public void setName(String name){
this.name = name;
}
public void getName(){
System.out.println("Hello, " + name);
}
}
This is the annotation based configuration file:
package com.test.SpringMaven2;
import org.springframework.context.annotation.*;
#Configuration
public class HelloWorldConfig{
#Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
}
This is my pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>SpringMaven2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>SpringMaven2</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
</dependencies>
</project>
I am running the following command in CMD to run the application:
java -cp {nameofresultjarfile} com.test.SpringMaven2.App
But getting the error messsage above
Any advice?
Thanks
Your pom.xml creates a jar file which contains only the classes defined in your project. But all the other dependencies (spring-core, spring-context-support) which are required by your application aren't included.
If your application is started within eclipse, eclipse integrates these required jar files to the classpath of the application and so it is able to run.
If your application is started from CMD the spring classes can't be found in the classpath and you get a java.lang.NoClassDefFoundError.
It's possible to name all the required jars manually when the application is started from CMD (classpath), but is much easier to created a so called self contained jar file, which has all of them already included. This can be done using maven-assembly-plugin.
An example how to create a self contained jar file can be found here.
The application in a self contained jar can be started now from CMD:
java -jar name_of_your_project-jar-with-dependencies.jar
I was getting the same error when running from Intellij as a main class (In Spring Boot project)
After opening Module settings, In the Deopendencies tab I saw that for spring-context for some reason the scope was provided, changing to compile/ even removing the scope fixed the issue for for me
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>## Put your desired version here ##</version>
</dependency>
In my similar case both #jaysee answer or:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.example.MyMainClass </mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
or
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.5.0</version>
helped.
The below fixed similar issue for me.
build plugins section should be put right after /dependencies:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.5.4</version>
<configuration>
<layout>ZIP</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
I was facing the same issue. I am using the intellij 2021 but the above solution didn't work. Also in eclipse it was working fine . The solution that worked for me was:
1)Go to edit run/debug configuraiton
2)Modify option
3)Check "include dependency with provided scope"
Related
I was working on a project involving reading from another process when I noticed that it kept throwing java.util.NoSuchElementException: No line found, so I made a Maven test application to check that it was Heroku's fault instead of my program's.
src/main/java/com/test/App.java:
package com.test;
import java.util.Arrays;
import java.util.Scanner;
import java.io.IOException;
public class App{
public static void main(String[] args) throws IOException{
System.out.println(new Scanner(new ProcessBuilder(Arrays.asList("java", "A")).start().getInputStream()).nextLine());
}
}
A.java:
public class A{
public static void main(String[] args){
System.out.println("Test");
}
}
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>test</artifactId>
<version>1.0</version>
<name>test</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<manifest>
<mainClass>com.test.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
After javac A.java, mvn install, and java -jar target/test-1.0.jar, it prints "Test" on my computer, but throws a NoSuchElementException in Heroku.
Full Stacktrace:
Exception in thread "main" java.util.NoSuchElementException: No line found
at java.util.Scanner.nextLine(Scanner.java:1540)
at com.test.App.main(App.java:7)
Does anyone know what's causing this and how to fix it?
Edit: Attatched Github repo to hopefully make it clearer
Edit Edit: Oddly, if I put A.java in src/main/java and use the command from #Malax's answer, it works, but I still don't get why Heroku isn't seeing the java file outside of src. Maybe it's trimming them out to save space?
The issue occurs because you're calling nextLine on Scanner without checking if there even is a line. You need to check with hasNext to ensure nextLine will not fail.
The underlying reason why you get no lines is that you're not specifying a classpath when invoking java. java will not be able to find your compiled A class without it and fail with something like
Error: Could not find or load main class A
Caused by: java.lang.ClassNotFoundException: A
on STDERR which you don't capture with getInputStream. You will be able to read the error message when you use getErrorStream instead (but then you won't get the STDOUT messages).
This has nothing to do with Heroku and I can only speculate why this is working for you locally. To provide java a classpath, you can use -cp:
ProcessBuilder processBuilder = new ProcessBuilder(Arrays.asList("java", "-cp", "target/classes", "A"));
Scanner scanner = new Scanner(processBuilder.start().getInputStream());
while (scanner.hasNext()) {
System.out.println(scanner.nextLine());
}
tl;dr: Why does this work locally but not when I deploy to my live App Engine project?
I'm trying to create a barebones servlet-based web app using the Java 11 version of App Engine. I'm updating a few projects from Java 8 to Java 11 following this guide. I'm also using this guide and this example. My goal is to use Jetty to run a very simple web app that serves a single static HTML file and a single servlet file in App Engine.
My web app works fine when I run locally:
mvn clean install
mvn exec:java -Dexec.args="target/app-engine-hello-world-1.war"
When I run these commands, both my index.html and my servlet URL work fine.
But when I deploy to my live site:
mvn package appengine:deploy
...the command succeeds, but when I navigate to my live URL, I get this error for both the HTML file and the servlet URL: "Error: Server Error. The server encountered an error and could not complete your request. Please try again in 30 seconds." If I look in the logs in the Cloud console, I see this error:
Error: Could not find or load main class io.happycoding.Main
Caused by: java.lang.ClassNotFoundException: io.happycoding.Main
Something is off with my setup, but I don't see anything obviously wrong.
Here are the files in my project:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.happycoding</groupId>
<artifactId>app-engine-hello-world</artifactId>
<version>1</version>
<packaging>war</packaging>
<properties>
<!-- App Engine currently supports Java 11 -->
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.4.31.v20200723</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>9.4.31.v20200723</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>9.4.31.v20200723</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-annotations</artifactId>
<version>9.4.31.v20200723</version>
<type>jar</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>io.happycoding.Main</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>appengine-maven-plugin</artifactId>
<version>2.2.0</version>
<configuration>
<projectId>happy-coding-gcloud</projectId>
<version>1</version>
</configuration>
</plugin>
</plugins>
</build>
</project>
src/main/appengine/app.yaml
runtime: java11
entrypoint: 'java -cp "*" io.happycoding.Main app-engine-hello-world-1.war'
src/main/java/io/happycoding/Main.java
package io.happycoding;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.webapp.Configuration.ClassList;
import org.eclipse.jetty.webapp.WebAppContext;
import io.happycoding.servlets.HelloWorldServlet;
/** Simple Jetty Main that can execute a WAR file when passed as an argument. */
public class Main {
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println("Usage: need a relative path to the war file to execute");
System.exit(1);
}
System.setProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.StrErrLog");
System.setProperty("org.eclipse.jetty.LEVEL", "INFO");
Server server = new Server(8080);
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
webapp.setWar(args[0]);
ClassList classlist = ClassList.setServerDefault(server);
// Enable Annotation Scanning.
classlist.addBefore(
"org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
"org.eclipse.jetty.annotations.AnnotationConfiguration");
server.setHandler(webapp);
server.join();
}
}
src/main/webapp/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Google Cloud Hello World</title>
</head>
<body>
<h1>Google Cloud Hello World</h1>
<p>This is a sample HTML file. Click here to see content served from a servlet.</p>
<p>Learn more at HappyCoding.io.</p>
</body>
</html>
src/main/java/io/happycoding/servlets/HelloWorldServlet.java
package io.happycoding.servlets;
import java.io.IOException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
#WebServlet("/hello")
public class HelloWorldServlet extends HttpServlet {
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html;");
response.getOutputStream().println("<h1>Hello world!</h1>");
}
}
I'm guessing something is off with how I'm setting the classpath of the live site, but I don't see anything obviously wrong.
With the packaging property in pom.xml set to war, I get a .war file with these contents:
index.html
META-INF/MANIFEST.MF
META-INF/maven/io.happycoding/app-engine-hello-world/pom.properties
META-INF/maven/io.happycoding/app-engine-hello-world/pom.xml
WEB-INF/classes/io/happycoding/Main.class
WEB-INF/classes/io/happycoding/servlets/HelloWorldServlet.class
WEB-INF/classes/lib/asm-7.3.1.jar
WEB-INF/classes/lib/asm-analysis-7.3.1.jar
WEB-INF/classes/lib/asm-commons-7.3.1.jar
WEB-INF/classes/lib/asm-tree-7.3.1.jar
WEB-INF/classes/lib/javax.annotation-api-1.3.jar
WEB-INF/classes/lib/javax.servlet-api-4.0.1.jar
WEB-INF/classes/lib/jetty-annotations-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-http-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-io-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-jndi-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-plus-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-security-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-server-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-servlet-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-util-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-webapp-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-xml-9.4.31.v20200723.jar
If I change the packaging property in pom.xml to jar, then I get a .jar file with these contents:
io/happycoding/Main.class
io/happycoding/servlets/HelloWorldServlet.class
META-INF/MANIFEST.MF
META-INF/maven/io.happycoding/app-engine-hello-world/pom.properties
META-INF/maven/io.happycoding/app-engine-hello-world/pom.xml
And I get this error in the logs for the live site instead:
Error: Unable to initialize main class io.happycoding.Main
Caused by: java.lang.NoClassDefFoundError: org/eclipse/jetty/server/Handler
That feels like progress, but then I also get 404 errors in my live server, so I feel pretty stuck.
What do I need to change about my above setup to make it work both locally and on my live server?
Edit: I can see the following files in the App Engine debugger:
I tried adding this to my pom.xml file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.2</version>
<executions>
<execution>
<id>copy</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/appengine-staging
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
Then I see these file in the App Engine debugger:
But I still get the same error.
I believe that the problem is caused by my Main class being inside a .war file which has no effect on the classpath, which is why it can't be found.
How do I package my project up so it works locally and on my live server?
I think your problem is that you are including the Main class in the war itself, and App Engine is unable to find it.
As you can see in the GCP migration guide, the Main class is defined in an external dependency named simple-jetty-main.
With the execution of the maven-dependency-plugin this dependency is copied to the appengine-staging directory, making it accessible from the Java classpath.
This is the reason why the Main class can be found in the example proposed in the guide when executing the command from the app.yaml entrypoint:
entrypoint: 'java -cp "*" com.example.appengine.demo.jettymain.Main helloworld.war'
Therefore, the solution will be to include your Main class in another library, independent from the war file that you need to deploy.
Maybe you can create a library - as Google does with simple-jetty-main - that can reuse in your GCP projects for this task.
Just for testing, in order to confirm this point, you can use the simple-jetty-main library itself (you can clone the required code from https://github.com/GoogleCloudPlatform/java-docs-samples/tree/master/appengine-java11/appengine-simple-jetty-main). Install it, include the dependency in your pom.xml, include also the maven-dependency-plugin, and define your entrypoint as follows:
entrypoint: 'java -cp "*" com.example.appengine.demo.jettymain.Main app-engine-hello-world-1.war'
For your comments, you will prefer not to have the separation between the Main class and the rest of the code.
To meet that requirement we must first change the Main class so that Jetty can serve HelloWorldSevlet and the static content. The code is actually very similar to the one you provided. Please excuse the simplicity of the setup, it is based on web.xml file; if necessary, further development can be done to deal with annotations or whatever is deemed appropriate:
package io.happycoding;
import java.net.URL;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
public class Main {
public static final String WEBAPP_RESOURCES_LOCATION = "META-INF/resources";
public static void main(String[] args) throws Exception {
System.setProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.StrErrLog");
System.setProperty("org.eclipse.jetty.LEVEL", "INFO");
Server server = new Server(8080);
URL webAppDir = Thread.currentThread().getContextClassLoader().getResource(WEBAPP_RESOURCES_LOCATION);
if (webAppDir == null) {
throw new RuntimeException(String.format("Unable to find %s directory into the JAR file", WEBAPP_RESOURCES_LOCATION));
}
WebAppContext webAppContext = new WebAppContext();
webAppContext.setContextPath("/");
webAppContext.setDescriptor(WEBAPP_RESOURCES_LOCATION + "/WEB-INF/web.xml");
webAppContext.setResourceBase(webAppDir.toURI().toString());
webAppContext.setParentLoaderPriority(true);
server.setHandler(webAppContext);
server.start();
server.join();
}
}
The static resources can be loaded from a directory of your choice (it will be parameterized in the pom.xml).
For instance, I have created the src/main/webapp folder to store the static content.
In this folder, you also need to define - in this case, due to the way we setup Jetty - a WEB-INF directory with this web.xml file inside:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<servlet>
<servlet-name>HelloWorldServlet</servlet-name>
<servlet-class>io.happycoding.servlets.HelloWorldServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorldServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
This is a tree of my source code setup:
The pom.xml file is very similar to the one you provided. I only included the maven-resources-plugin to copy the web app static content to the jar file, and the maven-shade-plugin to generate an UberJar:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.happycoding</groupId>
<artifactId>app-engine-hello-world</artifactId>
<version>1</version>
<packaging>jar</packaging>
<properties>
<!-- App Engine currently supports Java 11 -->
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<failOnMissingWebXml>false</failOnMissingWebXml>
<!-- Directory where static content resides -->
<webapp.dir>./src/main/webapp</webapp.dir>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.4.31.v20200723</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>9.4.31.v20200723</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>9.4.31.v20200723</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-annotations</artifactId>
<version>9.4.31.v20200723</version>
<type>jar</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>io.happycoding.Main</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<id>copy-web-resources</id>
<phase>compile</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/classes/META-INF/resources</outputDirectory>
<resources>
<resource>
<directory>${webapp.dir}</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>io.happycoding.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>appengine-maven-plugin</artifactId>
<version>2.2.0</version>
<configuration>
<projectId>happy-coding-gcloud</projectId>
<version>1</version>
</configuration>
</plugin>
</plugins>
</build>
</project>
With this setup, you can run the application locally by executing the following command:
mvn exec:java
You can also run the program locally right from the java tool:
java -jar appengine-deploy-sample-1.jar
Sorry, I cannot test the setup in GCP but I think, that according to the migration guide, you can try to deploy the application without indicating the entrypoint in your app.yaml.
If it does not work, you can try to run the app by configuring an entrypoint similar to the following:
entrypoint: 'java -jar appengine-deploy-sample-1.jar'
Or maybe:
entrypoint: 'java -cp "*" -jar appengine-deploy-sample-1.jar'
I can not generate proper WAR file for Tomcat.
I am using MAVEN 3.6.1, Java 12.0.1 and IDE Eclipse. My app is working fine when I run it in eclipse (Run as > Spring Boot App) but the problem is when I am trying to run my WAR file after generate it.
I am doing java -jar .war and I am getting:
Error: Could not find or load main class com.blw.linemanager.Application
Caused by: java.lang.ClassNotFoundException: com.blw.linemanager.Application
I was googling and reading stackoverflow cause I found many post about it but still can not run it. What I am doing wrong?
After some reading I figured out that I have some how configure maven-war-plugin (am I right?) and in pom I did some changes but it does not help.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>bwl</groupId>
<artifactId>LineManager</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<start-class>com.blw.linemanager.Application</start-class>
<maven.compiler.source>12</maven.compiler.source>
<maven.compiler.target>12</maven.compiler.target>
</properties>
<build>
<finalName>LineManager</finalName>
<outputDirectory>${project.build.directory}</outputDirectory>
<plugins>
<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>
<configuration>
<release>12</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/META-INF</outputDirectory>
<resources>
<resource>
<directory>${basedir}/src/main/resources/META-INF</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<archive>
<manifest>
<classpathPrefix>${project.build.directory}/WEB-INF/classes</classpathPrefix>
<addClasspath>true</addClasspath>
<mainClass>com.blw.linemanager.Application</mainClass>
</manifest>
<manifestFile>${project.build.directory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
Also because on the beginning I was getting error 'no main manifest attribute' I add it and now it looks like this
Manifest-Version: 1.0
Created-By: Apache Maven ${maven.version}
Build-Jdk: ${java.version}
Is my way of think wrong? Should I be able to run .war file as java -jar .war or this is missunderstanding?
#SpringBootApplication
public class Application extends org.springframework.boot.web.support.SpringBootServletInitializer {
public static void main(String [] args) {
SpringApplication app = new SpringApplication(Application.class);
app.run(args);
}
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Application.class);
}
}
It is better to get a working spring boot application from here to avoid versions conflicts and the like.
For a war-file deployment (into a local tomcat for example), your application must extend SpringBootServletInitializer:
#SpringBootApplication
public class SpringBootTomcatApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(SpringBootTomcatApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(SpringBootTomcatApplication.class);
}
}
Change in your pom the packaging to war.
<packaging>war</packaging>
To generate a war-file you need just the spring-boot-maven-plugin:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
And yes you don't need the maven-war-plugin. Just for testing purposes let's annotate our application with #RestController and introduce a simple endpoint:
#RestController
#SpringBootApplication
public class SpringBootTomcatApplication extends SpringBootServletInitializer {
...
#RequestMapping(value = "/")
public String hello() {
return "Hello World from Tomcat";
}
}
In the Local terminal (in eclipse Ctrl+Alt+T) just enter mvn package than copy the generated war-file from target folder, paste it under the webapps folder of your local Tomcat, request http://localhost:8080/{your-application-name} and you should see the message Hello World from Tomcat.
Now you can add the dependencies you need and continue coding.
Add packaging type with version detail in pom.xml like
<packaging>jar</packaging>
or
<packaging>war</packaging>
Then, append build tag to define name of jar / war like,
<build>
<finalName>YOUR-APP_NAME</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Then, run your application with goal
clean package
to create jar/war in target folder.
Rename your war file to ROOT like ROOT.war
Last step to copy your created jar/war in tomcat webapps folder and start tomcat.
I am working on a Hello World application. My application is built with Maven (3.5.0), uses Apache Felix annotations, and is run in Apache Karaf (4.1.1). My application consists of a single component, called App, that should be started immediately. The bundle builds successfully. I can successfully install it into Karaf from my mvn repository. Karaf shows the bundle as "Active". The problem is that constructor and the activate method of my component (App) are never invoked. I need a second set of eyes to help me figure out why this happens. What am I missing in my pom.xml?
For completeness, I created an Activator class in my project that implements BundleActivator. I then instructed Maven to set my Bundle-Activator to this new class. Now, when I install my bundle in Karaf, I can see the log output from my Activator. The start method is being hit. So I know my bundle is actually starting. I just don't understand why my App component is never created and activated.
Here are the relevant files.
App.java
package myCompany;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
#Component(immediate=true)
public class App
{
public App()
{
System.out.println( "App constructed" );
}
#Activate
public void activate()
{
System.out.println( "App activated" );
}
}
Activator.java
package myCompany;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
public class Activator implements BundleActivator{
public void start(BundleContext context) throws Exception {
System.out.println("Activator started");
}
public void stop(BundleContext context) throws Exception {
System.out.println("Activator stopped");
}
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>myCompany</groupId>
<artifactId>myProject</artifactId>
<packaging>bundle</packaging>
<version>1.0-SNAPSHOT</version>
<name>myProject</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
<version>1.9.6</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
<version>1.24.0</version>
<executions>
<execution>
<id>generate-scr-scrdescriptor</id>
<goals>
<goal>scr</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<version>3.3.0</version>
<configuration>
<instructions>
<_dsannotations>*</_dsannotations>
<_metatypeannotations>*</_metatypeannotations>
<Bundle-Activator>myCompany.Activator</Bundle-Activator>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
Karaf does not include support for declarative services out of the box. You need to install the scr feature to activate DS support:
feature:install scr
You are using obsolete annotations from the org.apache.felix.scr.annotations package, which are not recognised or processed by bnd — they require an additional Maven plugin to work.
It would be better to migrate your code to use the OSGi standard annotations from the org.osgi.service.component.annotations package. See OSGi Compendium Release 6 specification, section 112.8.
I am trying to use NATTY by including it as a maven dependency. I just did the Hello, World Maven tutorial -- but am otherwise unfamiliar with Maven. The instructions on the natty site say to include natty as a dependency in the pom.xml. I have done so like this
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>my-app</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.joestelmach</groupId>
<artifactId>natty</artifactId>
<version>0.9</version>
</dependency>
</dependencies>
</project>
I then run $mvn package and the project builds successfully. I see one jar file in my /target: my-app-1.0-SNAPSHOT.jar so I assume that the natty dependencies are baked into that jar.
To test, I create a simple class in a file called Temporary.java to hold the natty demo code:
import com.joestelmach.natty.*;
import com.joestelmach.natty.generated.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
public class Temporary{
public static void main(String [] args) {
Parser parser = new Parser();
List groups = parser.parse("the day before next thursday");
for (DateGroup group : groups) {
List dates = group.getDates();
int line = group.getLine();
int column = group.getPosition();
String matchingValue = group.getText();
String syntaxTree = group.getSyntaxTree().toStringTree();
Map parseMap = group.getParseLocations();
boolean isRecurreing = group.isRecurring();
Date recursUntil = group.getRecursUntil();
}
}
}
But when I run $ javac -cp target/my-app-1.0-SNAPSHOT.jar Temporary.java I get
Temporary.java:1: error: package com.joestelmach.natty does not exist
import com.joestelmach.natty.*;
What am I doing wrong?
You need to make sure that when you package your jar using maven that your dependencies are included.
I believe you need to add this to your pom.xml
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass></mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
Make sure when running it you use the .jar that has the "jar-with-dependencies.jar" at the end. This will ensure that your natty dependency is included.