Skip to main content
Create JAX-RS Server

Create JAX-RS Server

This chapter publishes a small employee API with CXF's JAX-RS frontend. The resource returns JSON, accepts a new employee, and runs on the embedded Jetty transport so it can be tested immediately.

Dependencies

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-frontend-jaxrs</artifactId>
    <version>${cxf.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-transports-http-jetty</artifactId>
    <version>${cxf.version}</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-json-provider</artifactId>
    <version>2.17.0</version>
</dependency>

Model and resource

package com.example.rest;

public class Employee {
    private int id;
    private String name;
    private String role;

    public Employee() {
    }

    public Employee(int id, String name, String role) {
        this.id = id;
        this.name = name;
        this.role = role;
    }

    public int getId() { return id; }
    public void setId(int id) { this.id = id; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public String getRole() { return role; }
    public void setRole(String role) { this.role = role; }
}
package com.example.rest;

import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import java.util.ArrayList;
import java.util.List;

@Path("/employees")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class EmployeeResource {

    private final List<Employee> employees = new ArrayList<>();
    private int nextId = 1;

    @GET
    public List<Employee> list() {
        return employees;
    }

    @GET
    @Path("/{id}")
    public Employee find(@PathParam("id") int id) {
        return employees.stream()
            .filter(e -> e.getId() == id)
            .findFirst()
            .orElseThrow(() -> new NotFoundException("No employee " + id));
    }

    @POST
    public Employee create(Employee employee) {
        employee.setId(nextId++);
        employees.add(employee);
        return employee;
    }
}

The class-level annotations apply to every method. The @Path on find adds a segment, so the final URL is /employees/{id}.

Publish the endpoint

package com.example.rest;

import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;

public class RestServer {

    public static void main(String[] args) {
        JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();
        factory.setResourceClasses(EmployeeResource.class);
        factory.setResourceProvider(
            EmployeeResource.class,
            new SingletonResourceProvider(new EmployeeResource()));
        factory.setProvider(new JacksonJsonProvider());
        factory.setAddress("http://localhost:8080/api");

        factory.create();
        System.out.println("API: http://localhost:8080/api/employees");
    }
}

A singleton resource keeps the in-memory list between requests, which is convenient for a demo. Production resources usually delegate to a repository or service and stay stateless.

Exercise the API

curl -s http://localhost:8080/api/employees

curl -s -X POST http://localhost:8080/api/employees \
  -H "Content-Type: application/json" \
  -d '{"name":"Ada","role":"engineer"}'

curl -s http://localhost:8080/api/employees/1

Root and service listings

CXF can expose a service listing page for development. It is useful while learning, but disable it in production because it reveals endpoint names.

factory.setStaticSubresourceResolution(true);

Keep API paths stable and version them when a breaking change is needed. The base address is the version boundary: /api/v1 in front of the resource path makes future migrations easier.

Error responses

Returning a WebApplicationException produces the corresponding status code. For structured JSON errors, register an exception mapper as shown in the JAX-RS overview. Clients should receive the same error shape from every endpoint.