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
Related Documentation
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:
- Follow Spring Boot best practices
- Include comprehensive tests
- Update documentation when adding new features
- Ensure compatibility with supported Spring Boot versions