skip to Main Content

I have a server side project written in java including mavenand spring-boot
And I’m trying to run it in Docker.
I write the whole program in VSCODE and create a special Dockerfile for it.
Then I want to be able to create a jar from my project and when I build an image and run it in the container I can see server side.

this is my Dockerfile:

FROM maven:3.8.1-openjdk-11 AS build
WORKDIR /usr/src/app
COPY pom.xml .
COPY src ./src
RUN mvn package
ENTRYPOINT ["java","-jar","target/my-app-1.0.0.jar"]

this is my 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>src</groupId>
    <artifactId>my-app</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.10.RELEASE</version>
    </parent>

    <properties>
        <start-class>src.MyApplication</start-class>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.1.6</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.2.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>src.MyApplication</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

MyApplication.java:

package src;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

And my folder structure is like this:

 .
 ├── src
 |   └──controllers
 |   │  └──controller.java
 |   └──models
 |   │  └──classA.java
 |   |  └──classB.java 
 |   └──services
 |   |  └──service.java
 |   └──MyApplication.java
 ├── Dockerfile
 ├── pom.xml

When I run the docker build -t app command. There seems to be no problem and the build is successful, but when I later run the command docker run -p 8080:8080 app I get this error
Error: Could not find or load main class src.MyApplication Caused by: java.lang.ClassNotFoundException: src.MyApplication

Does anyone have an idea for a solution for me?

2

Answers


  1. The word src is confusing in several ways.

    By convention the source code is held in folder called src/main and then beneath that you’d normally make folders for your organisation name and application.

    So suppose you were ACME Corporation and had a domain name acme.com and your application was about fish, then you’d package all your code under the package name com.acme.fish (domain name reversed, then application name, etc).

    In java is that Classes needs to be in files that match the class name, and by convention those files should have initial capitals. So ClassA.java not classA.java.

    This then would be a more conventional structure:

    ├── Dockerfile
    ├── pom.xml
    └── src
        └── main
            └── com
                └── acme
                    └── fish
                        ├── MyApplication.java
                        ├── controllers
                        │   └── Controller.java
                        ├── models
                        │   ├── ClassA.java
                        │   └── ClassB.java
                        └── services
                            └── Service.java
    

    Then in your pom.xml <mainClass> would be:

    <mainClass>com.acme.fish.MyApplication</mainClass>
    

    Start by restructuring like this.

    Then if this still does not work, use an unzip tool and look at the structure of your zip file. In the classses folder you should end up with a com/acme/fish/MyApplication.class

    Login or Signup to reply.
  2. Couple of things that are wrong.

    1. You aren’t using Maven packaging, the java files should reside in src/main/java
    2. Don’t use the default package for your code, use some package.
    3. Don’t mix Spring Boot versions.
    4. Ditch spring-context dependency and the spring-boot-autoconfigure dependency, already included through the starters.
    5. Use the spring-boot-maven-plugin not the maven-jar-plugin.

    The corrected 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>src</groupId>
        <artifactId>my-app</artifactId>
        <version>1.0.0</version>
        <packaging>jar</packaging>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>3.2.5</version>
        </parent>
    
        <properties>
            <java.version>17</maven.compiler.source>
        </properties>
    
        <dependencies>
            <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>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>
    

    Move your classes to a base package something like io.maia and use src/main/java for the proper Maven structure.

    Spring Boot 3.x requires Java 17 or higher, so update your Dockerfile as well. You might also want to leverage a multistage build (1 stage for the build, 1 stage for actually running it).

    FROM maven:3.8-openjdk-17 AS build
    WORKDIR /usr/src/app
    COPY pom.xml .
    COPY src ./src
    RUN mvn package
    
    FROM openjdk:21-slim
    copy --from=build target/my-app-1.0.0.jar my-app-1.0.0.jar
    ENTRYPOINT ["java","-jar","my-app-1.0.0.jar"]
    

    Or if your only goal is to run the application in a container, ditch the Dockerfile all together and run mvn spring-boot:build-image instead to get a runnable and optimized image.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search