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)
方法。在内部它可能使用 switch
或 Map<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
值重命名为全部大写,MANAGER
、CUSTOMER
,
按照公约的建议,
那么您可以从使用幕后缓存的 .valueOf
方法中受益:
public static Role fromString(String string) {
return valueOf(string.toUpperCase());
}
在这种情况下,您无需担心自己构建缓存。
如果您提供无效的字符串值,
这将像上面的示例一样引发 IllegalArgumentException
(文本略有不同)。
我有这个枚举:
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)
方法。在内部它可能使用 switch
或 Map<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
值重命名为全部大写,MANAGER
、CUSTOMER
,
按照公约的建议,
那么您可以从使用幕后缓存的 .valueOf
方法中受益:
public static Role fromString(String string) {
return valueOf(string.toUpperCase());
}
在这种情况下,您无需担心自己构建缓存。
如果您提供无效的字符串值,
这将像上面的示例一样引发 IllegalArgumentException
(文本略有不同)。