解决 UriBuilder 中参数值与模板冲突的问题

本文旨在解决在使用 javax.ws.rs.core.UriBuilder 构建 URI 时,由于查询参数的值恰好包含类似模板的字符串(例如,{g}),导致 IllegalArgumentException: The template variable 'g' has no value 异常的问题。我们将介绍如何正确处理这种情况,确保 URI 构建成功。

问题分析

javax.ws.rs.core.UriBuilder 是一个用于构建 URI 的类,它允许我们通过链式调用来添加查询参数、路径片段等。然而,当查询参数的值包含形如 {...} 的字符串时,UriBuilder 会将其误认为是 URI 模板变量,并尝试在上下文中查找对应的值。如果找不到,就会抛出 IllegalArgumentException 异常。

例如,以下代码:

import javax.ws.rs.core.UriBuilder;
import java.net.URI;

public class UriBuilderExample {

    private static URI getUriForName(String name) {
        return URI.create("https://example.com/api");
    }

    public static void main(String[] args) {
        String name = "test";
        String key = "b4o3h4{g}fghg3";

        try {
            URI uri = UriBuilder.fromUri(getUriForName(name))
                .queryParam("name", name)
                .queryParam("key", key)
                .build();

            System.out.println(uri.toString());
        } catch (IllegalArgumentException e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}

在上面的例子中,key 的值为 "b4o3h4{g}fghg3",其中包含 {g}。当 UriBuilder 构建 URI 时,它会尝试找到名为 g 的模板变量,但由于不存在,因此会抛出异常。

解决方案:使用 toTemplate() 方法

为了避免将查询参数的值误认为 URI 模板变量,我们可以使用 UriBuilder.toTemplate() 方法。该方法将 UriBuilder 转换为 URI 模板,而不是直接构建 URI。这样,包含类似模板的字符串的参数值将不会被解析为模板变量。

修改后的代码如下:

import javax.ws.rs.core.UriBuilder;
import java.net.URI;

public class UriBuilderExample {

    private static URI getUriForName(String name) {
        return URI.create("https://example.com/api");
    }

    public static void main(String[] args) {
        String name = "test";
        String key = "b4o3h4{g}fghg3";

        try {
            URI uri = UriBuilder.fromUri(getUriForName(name))
                .queryParam("name", name)
                .queryParam("key", key)
                .toTemplate();

            System.out.println(uri.toString());
        } catch (IllegalArgumentException e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}

注意: toTemplate() 方法返回的是一个 URI 对象,但实际上它代表的是一个 URI 模板。 如果需要构建实际的 URI,可能需要进一步处理,例如使用 UriTemplate 类来填充模板变量。 在上面的例子中,我们只是为了演示如何避免 IllegalArgumentException 异常,并没有真正构建一个可用的 URI。

总结

当使用 javax.ws.rs.core.UriBuilder 构建 URI 时,如果查询参数的值可能包含类似模板的字符串,为了避免 IllegalArgumentException 异常,应该使用 toTemplate() 方法将 UriBuilder 转换为 URI 模板。 这样可以确保参数值被正确地包含在 URI 中,而不会被误认为是模板变量。