如何使用基于 JAX-RS 的 Restlet 将 @DefaultValue 自动映射到枚举参数? [英] How to automatically map @DefaultValue to an enum parameter using JAX-RS based Restlet?

查看:32
本文介绍了如何使用基于 JAX-RS 的 Restlet 将 @DefaultValue 自动映射到枚举参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Web API,用户可以(也可以不)传输 URL 参数,例如 birddog 等.

I have a web API where the user may (or may not) transfer an URL parameter like for example bird, dog etc.

我希望将这个参数映射到服务器端的枚举,例如:

I want this parameter to be mapped to an enum on the server side, something like:

@POST
@Path("/zoo")
public Response createNewAnimal(
                        @QueryParam("animal") 
                        @DefaultValue("CAT") AnimalType type 
                ) throws Exception 

...

public enum AnimalType {
    BIG_BIRD,
    SMALL_CAT;
}

但它不起作用!

在处理 Web 请求时,正在调用 Enum.valueOf().当然它失败了,因为用户用作 URL 参数的 birdEnum (AnimalType.BIG_BIRD) 中的标识符不匹配.

While processing the web request, Enum.valueOf() is being called. And of course it fails, because the bird that user uses as URL parameter doesn't match the identifier in the Enum (AnimalType.BIG_BIRD).

没有办法覆盖 valueOf() 方法(它是静态的......)并且设置构造函数没有帮助(它是相反的逻辑方向).

There is no way to override to valueOf() method (it's static...) and setting constructor doesn't help (it's the opposite logical direction).

所以也许你知道一个很好的解决方案,而不是仅仅使用 if...else...?

So maybe you know of a nice solution to this, instead of just using if...else...?

推荐答案

如果你有一个像这样的枚举:

If you have an enum like:

public enum AnimalType {
    BIG_BIRD, 
    SMALL_CAT, 
    MEDIUM_DOG;
}

那么为了让 JAX-RS 知道返回哪个实例,您的查询参数必须是 ?animal=BIG_BIRD?animal=SMALL_CAT?动物=MEDIUM_DOG.

then in order for JAX-RS to know what instance to return, your query parameter must be ?animal=BIG_BIRD, ?animal=SMALL_CAT or ?animal=MEDIUM_DOG.

将查询参数的值提供给枚举的 valueOf 静态方法以获取实例.当然,如果您发送诸如 bird 之类的其他内容,它不会匹配任何内容并且无法工作,因为 @QueryParam 期望:

The value of the query parameter is fed to the valueOf static method of the enum to get an instance. Off course, if you send something else like bird it won't match anything and it won't work because @QueryParam expects this:

带注释的参数、字段或属性的类型 T 必须:
- 成为原始类型
- 有一个接受单个字符串参数的构造函数
- 有一个名为 valueOf 的静态方法,它接受单个字符串参数(例如,参见 Integer.valueOf(String))
- Be List、Set 或 SortedSet,其中 T 满足以上 2 或 3.生成的集合是只读的.

The type T of the annotated parameter, field or property must either:
- Be a primitive type
- Have a constructor that accepts a single String argument
- Have a static method named valueOf that accepts a single String argument (see, for example, Integer.valueOf(String))
- Be List, Set or SortedSet, where T satisfies 2 or 3 above. The resulting collection is read-only.

这同样适用于 @DefaultValue.您必须指定@DefaultValue("BIG_BIRD")@DefaultValue("SMALL_CAT")@DefaultValue("MEDIUM_DOG"):

The same applies for the @DefaultValue also. You have to specify @DefaultValue("BIG_BIRD"), @DefaultValue("SMALL_CAT") or @DefaultValue("MEDIUM_DOG"):

@POST
@Path("/zoo")
public Response createNewAnimal(
        @QueryParam("animal") 
        @DefaultValue("SMALL_CAT") AnimalType type) {
    // ...
    return Response.ok().entity(type.toString()).build();
}

如果您不想将 Java 类型的名称公开给客户端,您可以将正确的查询字符串值转换为枚举实例.if ... else ... if 是实现此目的的一种非常简单的方法,但如果您想要更高级的东西,您可以创建这样的包装器:

If you don't want to expose the names on your Java types to the client, you can transform the proper query string value into an enum instance. An if ... else ... if is a very simple way to achieve this but if you want something fancier you could create a wrapper like this:

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class AnimalTypeWrapper {
    private static final Map<String, AnimalType> MAPPER = Collections
            .unmodifiableMap(new HashMap<String, AnimalType>() {
                {
                    put("bird", AnimalType.BIG_BIRD);
                    put("dog", AnimalType.MEDIUM_DOG);
                    put("cat", AnimalType.SMALL_CAT);
                }
            });

    private AnimalType type;

    public static AnimalTypeWrapper valueOf(String value) {
        AnimalType type = AnimalTypeWrapper.MAPPER.get(value.toLowerCase());
        if (type == null) {
            // if nothing found just set the desired default value
            type = AnimalType.SMALL_CAT;
        }
        return new AnimalTypeWrapper(type);
    }

    private AnimalTypeWrapper(AnimalType type) {
        this.type = type;
    }

    public AnimalType getType() {
        return this.type;
    }
}

并且在您的资源方法中有:

and in your resource method have:

@POST
@Path("/zoo")
public Response createNewAnimal(
        @QueryParam("animal") 
        AnimalTypeWrapper typeWrapper) {
    // ...
    AnimalType type = typeWrapper.getType();
    return Response.ok().entity(type.toString()).build();
}

这篇关于如何使用基于 JAX-RS 的 Restlet 将 @DefaultValue 自动映射到枚举参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆