Java 枚举:实例化枚举 "dynamically"(更像是一个 class 构造函数)以与 Jackson 一起使用

Java Enums: Instantiate Enum "dynamically" (more like a class constructor) to use with Jackson

我有这个枚举:

public enum Role {

Manager("manager"),
Customer("customer");

private String role;

Role(String role){
    this.role = role;
}
}

我有这个从 Http 请求中获得的 POJO(使用 Jerey 和 Jackson):

public class UserCredentials {

private String username;
private String password;
private Role role;

public UserCredentials() {
}

public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
}

public Role getRole() {
    return role;
}

public void setRole(Role role) {
    this.role = role;
}
}

最后一个 setter 会产生错误,因为 Jackson 真的不知道如何转换

{
"username": "shikloshi",
"password": "password",
"role": "admin"
}

对象(特别是 "role" 枚举)。

我试图将 setter 更改为:

public void setRole(String role) {
this.role = new Role(role);
}

这是做不到的。

有没有办法以更面向对象的方式调用枚举构造函数(或任何其他创建方式 - 例如 Jackson)(另一种方法是在 setter 中使用 switch-case)?

在这种情况下,一个常见的解决方案是在 Role 枚举中添加一个 public static Role fromString(String) 方法。在内部它可能使用 switchMap<String, Role> 缓存。

使用简单 switch 的示例:

public static Role fromString(String string) {
    switch (string) {
        case "manager": return Manager;
        case "customer": return Customer;
    }
    throw new IllegalArgumentException("Invalid role: " + string);
}

使用缓存的示例:

private static Map<String, Role> cache = new HashMap<>();
static {
    for (Role value : values()) {
        cache.put(value.role, value);
    }
}

public static Role fromString(String string) {
    Role role = cache.get(string);
    if (role == null) {
        throw new IllegalArgumentException("Invalid role: " + string);
    }
    return role;
}

实际上,正如 @realskeptic 在评论中指出的那样, 如果您将 enum 值重命名为全部大写,MANAGERCUSTOMER, 按照公约的建议, 那么您可以从使用幕后缓存的 .valueOf 方法中受益:

public static Role fromString(String string) {
    return valueOf(string.toUpperCase());
}

在这种情况下,您无需担心自己构建缓存。 如果您提供无效的字符串值, 这将像上面的示例一样引发 IllegalArgumentException(文本略有不同)。