Sop*_*hie 7 java enums jax-rs web
我有一个Web API,用户可能(或可能不)传输URL参数,例如bird,dog等等.
我希望此参数映射到服务器端的枚举,如:
@POST
@Path("/zoo")
public Response createNewAnimal(
@QueryParam("animal")
@DefaultValue("CAT") AnimalType type
) throws Exception
...
public enum AnimalType {
BIG_BIRD,
SMALL_CAT;
}
Run Code Online (Sandbox Code Playgroud)
但它不起作用!
在处理Web请求时,Enum.valueOf()正在调用.当然它失败了,因为该bird用户使用的URL参数与Enum(AnimalType.BIG_BIRD)中的标识符不匹配.
没有办法覆盖到valueOf()方法(它是静态的......),并且设置构造函数没有帮助(它是相反的逻辑方向).
所以也许你知道一个很好的解决方案,而不是只使用if ... else ...?
Bog*_*dan 15
如果你有一个枚举像:
public enum AnimalType {
BIG_BIRD,
SMALL_CAT,
MEDIUM_DOG;
}
Run Code Online (Sandbox Code Playgroud)
然后,为了让JAX-RS知道要返回的实例,您的查询参数必须是 ?animal=BIG_BIRD,?animal=SMALL_CAT 或者?animal=MEDIUM_DOG.
查询参数的值被提供给valueOf枚举的静态方法以获取实例.当然,如果你发送其他东西bird,它将无法匹配,它将无法正常工作,因为我@QueryParam希望这样:
注释参数,字段或属性的类型T必须:
- 是基本类型
- 具有接受单个String参数的构造函数
- 具有名为valueOf的静态方法,该方法接受单个String参数(例如,参见Integer. valueOf(String))
- Be List,Set或SortedSet,其中T满足上面的2或3.生成的集合是只读的.
同样适用于此@DefaultValue.你必须指定@DefaultValue("BIG_BIRD"),@DefaultValue("SMALL_CAT") 或@DefaultValue("MEDIUM_DOG"):
@POST
@Path("/zoo")
public Response createNewAnimal(
@QueryParam("animal")
@DefaultValue("SMALL_CAT") AnimalType type) {
// ...
return Response.ok().entity(type.toString()).build();
}
Run Code Online (Sandbox Code Playgroud)
如果您不希望将Java类型的名称公开给客户端,则可以将正确的查询字符串值转换为枚举实例.if ... else ...如果是一种非常简单的方法来实现这一目标,但如果你想要更高档的东西,你可以创建一个这样的包装器:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
并在您的资源方法中有:
@POST
@Path("/zoo")
public Response createNewAnimal(
@QueryParam("animal")
AnimalTypeWrapper typeWrapper) {
// ...
AnimalType type = typeWrapper.getType();
return Response.ok().entity(type.toString()).build();
}
Run Code Online (Sandbox Code Playgroud)
使用 JAX-RS 和 Jackson 2.5.0 进行枚举(反)序列化的行为让我绊倒了一段时间,所以我将尝试详细说明@Bogdan 的答案,并展示对我有用的方法。
我不清楚的是,@QueryParam并且@FormParam不遵循标准程序来反序列化枚举 - 因此,如果您尝试接受枚举作为查询参数,如下所示:
@GET
public Response getAnimals(@QueryParam("animalType") AnimalType animalType) {}
Run Code Online (Sandbox Code Playgroud)
...那么您的animalType参数将被正确反序列化的唯一方法是您的类型T(在我们的例子中,AnimalType)满足以下属性之一:
String参数的构造函数。valueOf或的静态方法fromString,它接受单个String参数(例如,参见Integer.valueOf(String))。ParamConverterProviderJAX-RS 扩展 SPI的注册实现,该实现返回一个ParamConverter能够对该类型进行“从字符串”转换的实例。List<T>,Set<T>或SortedSet<T>,其中T满足以上 2、3 或 4。生成的集合是只读的。...根据Java EE 7 @QueryParam 文档。
这意味着,除了为您的正常用例实现自定义(反)序列化之外,您还需要满足上面列出的五个条件之一。然后,只有这样!,您才能处理@QueryParam反序列化案例。
我发现处理正常(反)序列化情况和@QueryParam情况的一种简单方法是 a) 通过实现满足条件 #3 fromString(),以及 b) 实现一个包含序列化器和反序列化器的映射器类,后者将依赖fromString(),所以我们有一致的反序列化:
// Our example enum class...
@JsonSerialize(using = AnimalTypeMapper.Serializer.class)
@JsonDeserialize(using = AnimalTypeMapper.Deserializer.class)
public enum AnimalType {
CAT("cat"),
BIRD("bird"),
DOG("doggy");
private final String name;
AnimalType(String name) {
this.name = name;
}
private static Map<String, AnimalType> VALUES_BY_NAME = Arrays.stream(values())
.collect(Collectors.toMap(AnimalType::getName, Function.identity()));
public String getName() {
return name;
}
// Implementing this method allows us to accept AnimalType's as @QueryParam
// and @FormParam arguments. It's also used in our custom deserializer.
public static AnimalType fromString(String name) {
return VALUES_BY_NAME.getOrDefault(name, DOG);
}
}
// Our custom (de)serialization class...
public class AnimalTypeMapper {
public static class Serializer extends JsonSerializer<AnimalType> {
@Override
public void serialize(AnimalType animalType, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(animalType.getName());
}
}
public static class Deserializer extends JsonDeserializer<AnimalType> {
@Override
public AnimalType deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
return AnimalType.fromString(jsonParser.getValueAsString());
}
}
}
Run Code Online (Sandbox Code Playgroud)
希望有人会发现这很有帮助。我花了太多时间在这上面旋转我的轮子!
| 归档时间: |
|
| 查看次数: |
12207 次 |
| 最近记录: |