枚举接口

在web开发中我们常常会定义一些enum来表示常量,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
enum BlogType {
BLOG(1, "原创博文"),
REPRINT(2, "转载文章"),
QUESTION(3, "问答"),
VOTE(4, "投票"),
SUBJECT(5, "专栏");

private Integer code;
private String name;

BlogType(Integer code, String name) {
this.code = code;
this.name = name;
}

public Integer getCode() {
return code;
}

public String getName() {
return name;
}
}

以及:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
enum BlogStatus {
PRIVATE(1, "自己可见"),
FRIEND(2, "好友可见"),
ONLINE(3, "登陆用户可见"),
PUBLISH(4, "公开");
private Integer code;
private String name;

BlogStatus(Integer code, String name) {
this.code = code;
this.name = name;
}

public Integer getCode() {
return code;
}

public String getName() {
return name;
}
}

可以看出它们的结构一样,都有codename这两个属性,以及对应的getter方法,因此可以定义一个如下的接口:

1
2
3
4
5
6
public interface Common<C, N> {
C getCode();

N getName();

}

所有如上面的常量枚举类都可以实现该接口。

1
2
3
4
5
6
7
enum BlogType implements Common {
//...
}

enum BlogStatus implements Common {
//...
}

公用静态方法

我们可以在在Common接口中定义一个如下的静态方法:

1
2
3
4
5
static <E extends Enum<E> & Common, C> E getByCode(Class<E> clazz, C code) {
return Arrays.stream(clazz.getEnumConstants())
.filter(t -> t.getCode().equals(code))
.findFirst().orElse(null);
}

使用此方法可以根据code来查找指定的Common实现类中的值,比如:

1
2
Assert.assertEquals(BlogType.QUESTION, Common.getByCode(BlogType.class, BlogType.QUESTION.getCode()));
Assert.assertEquals(BlogStatus.PUBLISH, Common.getByCode(BlogType.class, BlogStatus.PUBLISH.getCode()));

自定义序列化

当我们定义如下的方法

1
2
3
4
5
6
7
8
9
@GetMapping("/consts")
public ApiResult consts() {
ApiResult result = new ApiResult();
Map<String, Object> consts = new HashMap<>();
consts.put("blogType", BlogType.values());
consts.put("blogStatus", BlogStatus.values());
result.setData(consts);
return result;
}

通过请求,得到的结果格式是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"code": 0,
"success": true,
"data": {
"blogStatus": [
"PRIVATE",
"FRIEND",
"ONLINE",
"PUBLISH"
],
"blogType": [
"BLOG",
"REPRINT",
"QUESTION",
"VOTE",
"SUBJECT"
]
}
}

而我们期待的到是格式是包含codename的键值对的形式,而不是以上的形式。通过在Common接口中添加以上方法可以实现:

1
2
3
4
5
6
@JsonValue
default Map<C, N> toMap() {
Map<C, N> map = new HashMap<>(1);
map.put(getCode(), getName());
return map;
}

此时再次通过页面请求,得到的结果将如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{
"code": 0,
"success": true,
"data": {
"blogStatus": [
{
"1": "自己可见"
},
{
"2": "好友可见"
},
{
"3": "登陆用户可见"
},
{
"4": "公开"
}
],
"blogType": [
{
"1": "原创博文"
},
{
"2": "转载文章"
},
{
"3": "问答"
},
{
"4": "投票"
},
{
"5": "专栏"
}
]
}
}

此外,如果想通过使用fastjsonJSON.toJSONString()也能得到如上格式的结果,可以让Common继承com.alibaba.fastjson.JSONAware,并在Common中实现JSONAwaretoJSONString方法:

1
2
3
4
@Override
default String toJSONString() {
return JSON.toJSONString(toMap());
}

以下代码将会通过:

1
Assert.assertEquals("{2:\"转载文章\"}", JSON.toJSONString(BlogType.REPRINT));

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONAware;
import com.fasterxml.jackson.annotation.JsonValue;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
* @author wf2311
*/
public interface Enums {
interface Common<C, N> extends JSONAware {
C getCode();

N getName();

static <E extends Enum<E> & Common, C> E getByCode(Class<E> clazz, C code) {
return Arrays.stream(clazz.getEnumConstants())
.filter(t -> t.getCode().equals(code))
.findFirst().orElse(null);
}

@JsonValue
default Map<C, N> toMap() {
Map<C, N> map = new HashMap<>(1);
map.put(getCode(), getName());
return map;
}

@Override
default String toJSONString() {
return JSON.toJSONString(toMap());
}

}

enum BlogType implements Common {
BLOG(1, "原创博文"),
REPRINT(2, "转载文章"),
QUESTION(3, "问答"),
VOTE(4, "投票"),
SUBJECT(5, "专栏");

private Integer code;
private String name;

BlogType(Integer code, String name) {
this.code = code;
this.name = name;
}

public Integer getCode() {
return code;
}

public String getName() {
return name;
}
}

enum BlogStatus implements Common {
PRIVATE(1, "自己可见"),
FRIEND(2, "好友可见"),
ONLINE(3, "登陆用户可见"),
PUBLISH(4, "公开");
private int code;
private String name;

BlogStatus(Integer code, String name) {
this.code = code;
this.name = name;
}

public Integer getCode() {
return code;
}

public String getName() {
return name;
}
}
}