Skip to main content

juneau-shaded-rest-server-springboot

The juneau-shaded-rest-server-springboot artifact bundles REST server functionality plus Spring Boot integration. At 3.8 MB, it provides everything needed for building Juneau REST services with Spring Boot.

What's Included

This artifact includes:

  • All modules from juneau-shaded-rest-server (core + REST server)
  • juneau-rest-server-springboot - Spring Boot auto-configuration and integration

Use Cases

Use juneau-shaded-rest-server-springboot when you need:

  • Spring Boot applications - Leverage Spring Boot's ecosystem
  • Auto-configuration - Automatic Juneau setup with Spring Boot
  • Spring dependency injection - Use @Autowired in REST resources
  • Spring Security integration - Leverage Spring's security framework
  • Spring ecosystem - Access to Spring Data, Spring Cloud, etc.

Maven Dependency

<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-shaded-rest-server-springboot</artifactId>
<version>${juneau.version}</version>
</dependency>

Bazel Dependency

maven_jar(
name = "juneau_rest_server_springboot",
artifact = "org.apache.juneau:juneau-shaded-rest-server-springboot:${juneau.version}",
)

# External dependencies
maven_jar(
name = "spring_boot_starter_web",
artifact = "org.springframework.boot:spring-boot-starter-web:3.2.0",
)

java_library(
name = "my_spring_api",
srcs = glob(["src/**/*.java"]),
deps = [
"@juneau_rest_server_springboot//jar",
"@spring_boot_starter_web//jar",
],
)

External Dependencies

juneau-shaded-rest-server-springboot requires:

Required

  • Spring Boot Starter Web 3.0+ - Spring Boot web support
  • Jakarta Servlet API 6.1+ - Servlet specification (transitively from Spring Boot)

Optional

  • Spring Boot Starter Security - For Spring Security integration
  • Jakarta XML Bind API 3.0+ - For XML serialization
  • Apache Jena - For RDF support

Example Usage

Spring Boot Application

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);
}
}

REST Resource with Spring Integration

import org.apache.juneau.rest.annotation.*;
import org.apache.juneau.rest.springboot.*;
import org.springframework.beans.factory.annotation.Autowired;

@Rest(
path="/api/pets",
title="Pet Store API"
)
public class PetResource extends SpringRestServlet {

@Autowired
private PetService petService; // Spring bean injection

@RestGet
public List<Pet> getAllPets() {
return petService.findAll();
}

@RestGet(path="/{id}")
public Pet getPet(@Path long id) {
return petService.findById(id)
.orElseThrow(() -> new NotFound("Pet not found"));
}

@RestPost
public Pet createPet(@Content Pet pet) {
return petService.save(pet);
}
}

Spring Configuration

import org.springframework.context.annotation.Configuration;
import org.apache.juneau.rest.springboot.JuneauRestInitializer;

@Configuration
public class JuneauConfig implements JuneauRestInitializer {

@Override
public void init(SpringRestServletBuilder builder) {
builder
.defaultAccept("application/json")
.defaultContentType("application/json")
.maxInput("10M");
}
}

Application Properties

# application.properties

# Juneau settings
juneau.defaultAccept=application/json
juneau.defaultContentType=application/json
juneau.maxInput=10M

# Server settings
server.port=8080
server.servlet.context-path=/

# Logging
logging.level.org.apache.juneau=DEBUG

Spring Security Integration

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.httpBasic();

return http.build();
}
}

Accessing Security Context

@Rest(path="/api/users")
public class UserResource extends SpringRestServlet {

@RestGet(path="/me")
public User getCurrentUser() {
Authentication auth = SecurityContextHolder.getContext()
.getAuthentication();

String username = auth.getName();
return userService.findByUsername(username);
}
}

Spring Data Integration

import org.springframework.data.jpa.repository.JpaRepository;

public interface PetRepository extends JpaRepository<Pet, Long> {
List<Pet> findBySpecies(String species);
}

@Rest(path="/api/pets")
public class PetResource extends SpringRestServlet {

@Autowired
private PetRepository petRepository;

@RestGet
public List<Pet> getAllPets(
@Query("species") String species
) {
if (species != null)
return petRepository.findBySpecies(species);
return petRepository.findAll();
}
}

Transaction Management

import org.springframework.transaction.annotation.Transactional;

@Rest(path="/api/orders")
public class OrderResource extends SpringRestServlet {

@Autowired
private OrderService orderService;

@RestPost
@Transactional
public Order createOrder(@Content Order order) {
// Transactional operation
return orderService.create(order);
}
}

Exception Handling with Spring

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(
EntityNotFoundException ex
) {
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse(ex.getMessage()));
}
}

Swagger Integration

@Rest(
path="/api",
swagger=@Swagger(
title="Pet Store API",
version="1.0",
description="REST API for Pet Store",
contact=@Contact(
name="Support Team",
email="support@example.com"
),
license=@License(
name="Apache 2.0",
url="http://www.apache.org/licenses/LICENSE-2.0.html"
)
)
)
public class PetStoreApi extends SpringRestServlet {
// Swagger UI at: http://localhost:8080/api/swagger
// OpenAPI JSON at: http://localhost:8080/api/openapi.json
}

Multi-Module Spring Boot Application

// Main application
@SpringBootApplication
@ComponentScan(basePackages = {
"com.example.api",
"com.example.service"
})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}

// REST resources in com.example.api
@Rest(path="/users")
@Component
public class UserResource extends SpringRestServlet {
@Autowired
private UserService userService;
// ...
}

// Services in com.example.service
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
// ...
}

Features

Spring Boot Auto-Configuration

  • Automatic servlet registration
  • Property-based configuration
  • Actuator integration
  • Metrics and health checks

Spring Ecosystem Integration

  • Spring Data - Database access
  • Spring Security - Authentication/authorization
  • Spring Cloud - Microservices patterns
  • Spring Cache - Caching abstraction
  • Spring Scheduling - Task scheduling

Juneau Features

All features from juneau-shaded-rest-server plus:

  • Spring bean injection in REST resources
  • Access to Spring ApplicationContext
  • Integration with Spring's exception handling
  • Spring's AOP capabilities

Testing

Spring Boot Test

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@ExtendWith(SpringExtension.class)
public class PetResourceTest {

@Autowired
private TestRestTemplate restTemplate;

@Test
public void testGetAllPets() {
ResponseEntity<Pet[]> response = restTemplate
.getForEntity("/api/pets", Pet[].class);

assertEquals(HttpStatus.OK, response.getStatusCode());
assertTrue(response.getBody().length > 0);
}
}

MockMvc Integration

import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@WebMvcTest(PetResource.class)
public class PetResourceMockMvcTest {

@Autowired
private MockMvc mockMvc;

@MockBean
private PetService petService;

@Test
public void testGetPet() throws Exception {
Pet pet = new Pet(1L, "Fluffy", "cat");
when(petService.findById(1L))
.thenReturn(Optional.of(pet));

mockMvc.perform(get("/api/pets/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("Fluffy"));
}
}

Migration from Individual Modules

Before:

<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-rest-server</artifactId>
<version>${juneau.version}</version>
</dependency>
<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-rest-server-springboot</artifactId>
<version>${juneau.version}</version>
</dependency>

After:

<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-shaded-rest-server-springboot</artifactId>
<version>${juneau.version}</version>
</dependency>

Next Steps

Discussion

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