I’ve been trying to get back into blogging and plan to write more concise posts that are helpful without taking up too much of your time.
In this post, I’ll briefly explain how to debug a remote Spring Boot application running inside a Docker container.
Link: https://start.spring.io/
Dependencies:
Now, open this project in your preferred IDE.
package com.deriklima.postsloader;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.List;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
@RequestMapping("/posts")
public class PostsloaderApplication {
public static void main(String[] args) {
SpringApplication.run(PostsloaderApplication.class, args);
}
@GetMapping
ResponseEntity<List<Post>> posts() {
List<Post> posts;
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://jsonplaceholder.typicode.com/posts"))
.header("Accept", "application/json")
.GET()
.build();
try (HttpClient client = HttpClient.newHttpClient()) {
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
if (response.statusCode() == 200) {
final ObjectMapper objectMapper = new ObjectMapper();
posts = objectMapper.readValue(response.body(), new TypeReference<>() {});
} else {
return ResponseEntity.status(response.statusCode()).build();
}
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
return ResponseEntity.ok(posts);
}
record Post(String id, String userId, String title, String body) {}
}
Maven:
./mvnw clean package
Maven:
./mvnw spring-boot:run
curl -H "Accept: application/json" http://localhost:8080/posts
# If you have "jq" installed, you can pipe the results to it to look nicer
curl -H "Accept: application/json" http://localhost:8080/posts | jq
I’ve placed the Dockerfile in a folder called ‘docker,’ and my commands to build the image will reflect that.
ARG JDK_IMAGE_VERSION=21
FROM openjdk:${JDK_IMAGE_VERSION}
RUN adduser --system postsloader
USER postsloader
COPY --chown=postsloader ./target/*.jar /opt/postsloader/app.jar
WORKDIR /opt/postsloader
# Expose the debug port
EXPOSE 5005
# Expose the application port (default Spring Boot port)
EXPOSE 8080
ENTRYPOINT ["java", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005", "-jar", "/opt/postsloader/app.jar"]
Keep in mind that you should be in the root folder of your project before running the command below. Also, you can name it whatever you like (the -t parameter).
docker build -f docker/Dockerfile -t derikjl/postsloader .
docker run --name postsloader -p 8080:8080 -p 5005:5005 derikjl/postsloader
For IntelliJ IDEA:
For Eclipse:
Add breakpoints in your Spring Boot code.
Call the endpoint we’ve just created
curl -H "Accept: application/json" http://localhost:8080/posts
Debugger Cannot Connect
Breakpoints Not Hit
Gradle instead of Maven