Skip to main content

juneau-examples-rest-springboot

The juneau-examples-rest-springboot module demonstrates how to integrate Apache Juneau REST servers with Spring Boot for enterprise-grade microservice applications.

Overview​

This example shows how to leverage Spring Boot's powerful features while using Juneau's REST capabilities. It demonstrates Spring Boot integration patterns, dependency injection, and enterprise deployment scenarios.

Getting Started​

Prerequisites​

  • Java 17+
  • Maven 3.6+
  • Spring Boot 2.0+ (tested with Spring Boot 2.7+)

Dependencies​

Add the following dependencies to your project:

<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-rest-server-springboot</artifactId>
<version>${juneau.version}</version>
</dependency>
<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-examples-rest</artifactId>
<version>${juneau.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>${spring.boot.version}</version>
</dependency>

Example Implementation​

Main Application Class​

The example demonstrates Spring Boot integration with Juneau REST:

package org.apache.juneau.examples.rest.springboot;

import org.apache.juneau.rest.annotation.*;
import org.apache.juneau.rest.springboot.*;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.*;
import org.springframework.boot.web.servlet.*;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Controller;

@SpringBootApplication
@Controller
public class App {

public static void main(String[] args) {
try {
new SpringApplicationBuilder(App.class).run(args);
System.out.println("Initialized. App available on http://localhost:5000");
} catch (Exception e) {
e.printStackTrace();
}
}

@Bean
public RootResources getRootResources() {
return new RootResources();
}

@Bean
public HelloWorldResource getHelloWorldResource() {
return new HelloWorldResource();
}

@Bean
public HelloWorldMessageProvider getHelloWorldMessageProvider() {
return new HelloWorldMessageProvider("Hello Spring injection user!");
}

@Bean
public ServletRegistrationBean<jakarta.servlet.Servlet> getRootServlet(RootResources rootResources) {
return new ServletRegistrationBean<>(rootResources, "/*");
}
}

Key Features​

  • Spring Boot Integration - Full Spring Boot auto-configuration
  • Dependency Injection - Spring's IoC container integration
  • Bean Management - REST resources as Spring beans
  • Actuator Support - Built-in monitoring and management
  • Configuration Properties - Spring Boot configuration support

Spring Boot Integration Patterns​

REST Resource as Spring Bean​

@Bean
public HelloWorldResource getHelloWorldResource() {
return new HelloWorldResource();
}

Dependency Injection in REST Resources​

@Rest(path="/hello")
public class HelloWorldResource extends SpringRestServlet {

@Autowired
private HelloWorldMessageProvider messageProvider;

@RestGet
public String getMessage() {
return messageProvider.getMessage();
}
}

Servlet Registration​

@Bean
public ServletRegistrationBean<jakarta.servlet.Servlet> getRootServlet(RootResources rootResources) {
return new ServletRegistrationBean<>(rootResources, "/*");
}

Configuration​

Application Properties​

Configure the application using application.properties:

# Server configuration
server.port=5000
server.servlet.context-path=/

# Spring Boot configuration
spring.application.name=juneau-examples-rest-springboot
spring.profiles.active=dev

# Juneau REST configuration
juneau.rest.path=/api
juneau.rest.serializers=JsonSerializer,XmlSerializer
juneau.rest.parsers=JsonParser,XmlParser

# Logging configuration
logging.level.org.apache.juneau=DEBUG
logging.level.org.springframework=INFO

YAML Configuration​

Alternative YAML configuration:

server:
port: 5000
servlet:
context-path: /

spring:
application:
name: juneau-examples-rest-springboot
profiles:
active: dev

juneau:
rest:
path: /api
serializers:
- JsonSerializer
- XmlSerializer
parsers:
- JsonParser
- XmlParser

logging:
level:
org.apache.juneau: DEBUG
org.springframework: INFO

Running the Example​

Development Mode​

# Clone the repository
git clone https://github.com/apache/juneau.git
cd juneau

# Build the project
mvn clean package

# Run the Spring Boot example
mvn spring-boot:run -pl juneau-examples/juneau-examples-rest-springboot

Production Deployment​

# Run with specific profile
java -jar juneau-examples-rest-springboot.jar --spring.profiles.active=prod

# Run with custom configuration
java -jar juneau-examples-rest-springboot.jar --server.port=8080

# Run with external configuration
java -jar juneau-examples-rest-springboot.jar --spring.config.location=classpath:/application-prod.properties

Available Endpoints​

The application provides all REST examples from the juneau-examples-rest module:

  • Root Resources - GET /api/
  • Hello World - GET /api/helloWorld
  • Request Echo - GET /api/requestEcho
  • Photos - GET /api/photos
  • DTO Bean Examples - Various DTO bean demonstration endpoints

Spring Boot Actuator Endpoints​

Additional Spring Boot management endpoints:

  • Health Check - GET /actuator/health
  • Application Info - GET /actuator/info
  • Metrics - GET /actuator/metrics
  • Environment - GET /actuator/env

Advanced Features​

Profile-Based Configuration​

@Configuration
@Profile("dev")
public class DevConfig {

@Bean
public HelloWorldMessageProvider devMessageProvider() {
return new HelloWorldMessageProvider("Hello from DEV environment!");
}
}

@Configuration
@Profile("prod")
public class ProdConfig {

@Bean
public HelloWorldMessageProvider prodMessageProvider() {
return new HelloWorldMessageProvider("Hello from PROD environment!");
}
}

Custom Configuration Properties​

@ConfigurationProperties(prefix = "juneau.rest")
public class JuneauRestProperties {

private String path = "/api";
private List<String> serializers = Arrays.asList("JsonSerializer");
private List<String> parsers = Arrays.asList("JsonParser");

// Getters and setters
}

Conditional Bean Creation​

@Bean
@ConditionalOnProperty(name = "juneau.rest.console.enabled", havingValue = "true")
public RestConsole getRestConsole() {
return new RestConsole();
}

Testing​

Unit Tests​

@SpringBootTest
@AutoConfigureTestDatabase
class HelloWorldResourceTest {

@Autowired
private HelloWorldResource helloWorldResource;

@Test
void testGetMessage() {
String message = helloWorldResource.getMessage();
assertThat(message).isNotNull();
}
}

Integration Tests​

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class RestIntegrationTest {

@Autowired
private TestRestTemplate restTemplate;

@Test
void testHelloWorldEndpoint() {
ResponseEntity<String> response = restTemplate.getForEntity("/api/helloWorld", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
}

Deployment Options​

JAR Deployment​

# Create executable JAR
mvn clean package

# Run standalone
java -jar target/juneau-examples-rest-springboot-${version}.jar

Docker Deployment​

FROM openjdk:17-jre-slim
COPY target/juneau-examples-rest-springboot.jar app.jar
EXPOSE 5000
ENTRYPOINT ["java", "-jar", "/app.jar"]

Kubernetes Deployment​

apiVersion: apps/v1
kind: Deployment
metadata:
name: juneau-springboot-example
spec:
replicas: 3
selector:
matchLabels:
app: juneau-springboot-example
template:
metadata:
labels:
app: juneau-springboot-example
spec:
containers:
- name: app
image: juneau-springboot-example:latest
ports:
- containerPort: 5000
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"

Monitoring and Management​

Spring Boot Actuator​

Enable comprehensive monitoring:

# Actuator configuration
management.endpoints.web.exposure.include=health,info,metrics,env
management.endpoint.health.show-details=always
management.info.env.enabled=true

Custom Health Indicators​

@Component
public class JuneauHealthIndicator implements HealthIndicator {

@Override
public Health health() {
// Custom health check logic
return Health.up()
.withDetail("juneau", "Available")
.build();
}
}

Metrics Integration​

@Component
public class JuneauMetrics {

private final MeterRegistry meterRegistry;

public JuneauMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}

public void recordRequest(String endpoint) {
meterRegistry.counter("juneau.requests", "endpoint", endpoint).increment();
}
}

Best Practices​

Configuration Management​

  • Use Spring profiles for environment-specific configuration
  • Implement configuration validation
  • Use @ConfigurationProperties for type-safe configuration

Dependency Injection​

  • Prefer constructor injection over field injection
  • Use @Qualifier for multiple bean implementations
  • Implement proper bean lifecycle management

Error Handling​

  • Use Spring's @ControllerAdvice for global error handling
  • Implement custom exception handlers
  • Provide meaningful error responses

Security​

  • Integrate with Spring Security
  • Use HTTPS in production
  • Implement proper authentication and authorization
juneau-examples-rest - REST API examplesjuneau-examples-rest-jetty - Jetty examplesJuneau REST Server Spring Boot - Spring Boot integrationJuneau REST Server Basics - REST server fundamentals

Source Code​

The complete source code for the Spring Boot examples is available in the juneau-examples-rest-springboot module of the Apache Juneau project.

Contributing​

To contribute improvements to the Spring Boot examples:

  1. Follow Spring Boot best practices
  2. Include comprehensive tests
  3. Update documentation when adding new features
  4. Ensure compatibility with supported Spring Boot versions
Discussion

Share feedback or follow-up questions for this page directly through GitHub.