JAX-RS Path Segments and Matrix Parameters

Matrix Parameters are different from Query Parameters. Query parameters are typically placed at the end of the URI using the ? character. Matrix Parameters can be placed in every URI segment using the ; character. This tutorial shows you how to retrieve the matrix parameters, either programatically or injecting with @MatrixParam annotation.

JAX-RS Path Segments and Matrix Parameters with @PathParam

The @PathParam JAX-RS annotation can not only inject the value of a path parameter, it can also inject instances of PathSegment.

Get Single Path Segment

We can inject an instance of PathSegment using the @PathParam annotation. Using this PathSegment we can obtain the value of the actual URI segment using the getPath() method. We can also obtain a map containing all the matrix parameters applied to that particular URI segment using the getMatrixParameters().

package com.memorynotfound.rs;

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import java.util.List;

@Path("/cars")
public class CarResource {

    @GET
    @Path("{brand}/{model}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getCars(@PathParam("brand") String brand,
                            @PathParam("model") PathSegment car){

        String model = car.getPath();
        String color = car.getMatrixParameters().getFirst("color");

        System.out.println("brand: " + brand);
        System.out.println("model: " + model);
        System.out.println("color: " + color);

        return Response.ok().build();
    }

}

In the previous code, suppose we make a HTTP GET request with the following path. Notice we included a matrix parameter color for the path parameter model.

GET /cars/BMW/320;color=black

The service will print out the following info to the console:

brand: BMW
model: 320
color: black

Get Multiple Path Segment

You can match multiple URI segments with a single path parameter. You do this by injecting a list of PathSegments for that single path parameter.

package com.memorynotfound.rs;

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import java.util.List;

@Path("/cars")
public class CarResource {

    @GET
    @Path("{brand}/{model: .+}/{year}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getCars(@PathParam("brand") String brand,
                            @PathParam("model") List<PathSegment> cars,
                            @PathParam("year") Integer year){

        System.out.println("brand: " + brand);
        for (PathSegment segment : cars){
            System.out.println("model: " + segment.getPath());
            for (String name : segment.getMatrixParameters().keySet()){
                String value = segment.getMatrixParameters().getFirst(name);
                System.out.println("\tmatrix param name: " + name + " value: " + value);
            }
        }
        System.out.println("year: " + year);

        return Response.ok().build();
    }

}

In this example we are mapping the model BMW and E92 to the same model path parameter. We also provide different matrix parameters to these path segments.

GET /cars/BMW/E92;color=black/M3;maker=john/2015

This will produce the following output:

brand: BMW
model: E92
	matrix param name: color value: black
model: M3
	matrix param name: maker value: john
year: 2015

Get Path Segments and Matrix Parameters Programatically

Instead of injecting the PathSegment using the @PathParam, we can also retrieve these programatically by injecting an instance of UriInfo with the @Context annotation. Next we can get a list of the PathSegment using the getPathSegments().

package com.memorynotfound.rs;

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import java.util.List;

@Path("/orders")
public class OrderResource {

    @GET
    @Path("{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getOrders(@Context UriInfo info){

        PathSegment model = info.getPathSegments().get(1);
        System.out.println("id: " + model.getPath());
        for (String name : model.getMatrixParameters().keySet()){
            String value = model.getMatrixParameters().getFirst(name);
            System.out.println("\tmatrix param name: " + name + " value: " + value);
        }

        return Response.ok().build();
    }

}

We provide a matrix parameter to the id path parameter.

GET /orders/4492;delivery=immediate

This generates the following output:

id: 4492
	matrix param name: delivery value: immediate

Get Matrix Parameters with @MatrixParam

We can also inject the matrix parameters immediately using the @MatrixParam JAX-RS annotation.

Note: when using the @MatrixParam and you have repeating matrix parameters defined in your URI that are applied to many different path segments it is uncertain which matrix parameter is used. And if this is the case you should go back and use the PathSegment to get the matrix parameters.
package com.memorynotfound.rs;

import javax.ws.rs.*;
import javax.ws.rs.core.*;

@Path("/products")
public class ProductResource {

    @GET
    @Path("{id}/{status}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getProducts(@PathParam("id") String id,
                                @MatrixParam("delivery") String delivery,
                                @PathParam("status") String status){

        System.out.println("id: " + id);
        System.out.println("delivery: " + delivery);
        System.out.println("status: " + status);

        return Response.ok().build();
    }

}

Notice we registered 2 matrix parameters for different path segments. As we can only map a single matrix parameter with the @MatrixParam annotation, it is uncertain which parameter will be mapped.

GET /products/4492;delivery=immediate/active;delivery=delayed

Produces the following output

id: 4492
delivery: delayed
status: active

Sending Matrix Parameters with JAX-RS Client API

This example shows you how to pass matrix parameters using JAX-RS Client API. By building each path separately you can register separate matrix parameters for each URI Path Segment. You can add a matrix parameter using the WebTarget#matrixParam(name, value) method.

package com.memorynotfound.rs;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Response;

public class RunClient {

    public static void main(String... args){
        Client client = ClientBuilder.newClient();

        Response response = client
                .target("http://localhost:8081/jaxrs-matrix-param/api/cars/{brand}")
                .resolveTemplate("brand", "BMW")
                .path("E92").matrixParam("color", "black")
                .path("M3").matrixParam("maker", "john")
                .path("2015")
                .request()
                .get();

        if (response.getStatus() == 200){
            System.out.println("Response: " + response.readEntity(String.class));
        }
        client.close();
    }
}

References

Download

You may also like...