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