Skip to content

Commit 4ac5e8a

Browse files
authored
refactor: 优化对枚举类型的支持 (#90)
* refactor: 优化对枚举类型的支持 Signed-off-by: zhouhao <[email protected]> * refactor: 优化 Signed-off-by: zhouhao <[email protected]> --------- Signed-off-by: zhouhao <[email protected]>
1 parent 93d6fd6 commit 4ac5e8a

File tree

8 files changed

+139
-30
lines changed

8 files changed

+139
-30
lines changed

hsweb-easy-orm-core/src/main/java/org/hswebframework/ezorm/core/ObjectPropertyOperator.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import lombok.SneakyThrows;
44

5+
import java.util.Objects;
56
import java.util.Optional;
67

78
public interface ObjectPropertyOperator {
@@ -10,13 +11,33 @@ public interface ObjectPropertyOperator {
1011

1112
void setProperty(Object object, String name, Object value);
1213

14+
/**
15+
* 对比两个对象
16+
* @param left left
17+
* @param right right
18+
* @return
19+
*/
20+
@SuppressWarnings("all")
21+
default int compare(Object left, Object right) {
22+
if (Objects.equals(left, right)) {
23+
return 0;
24+
}
25+
if (left.getClass() == right.getClass() && left instanceof Comparable) {
26+
return ((Comparable) left).compareTo(right);
27+
}
28+
if (left instanceof Number && right instanceof Number) {
29+
return Double.compare(((Number) left).doubleValue(), ((Number) right).doubleValue());
30+
}
31+
return -1;
32+
}
33+
1334
@SneakyThrows
1435
default Optional<Class<?>> getPropertyType(Object object, String name) {
1536
try {
1637
return Optional.of(object
17-
.getClass()
18-
.getDeclaredField(name)
19-
.getType());
38+
.getClass()
39+
.getDeclaredField(name)
40+
.getType());
2041
} catch (Throwable e) {
2142
return Optional.empty();
2243
}

hsweb-easy-orm-rdb/src/main/java/org/hswebframework/ezorm/rdb/codec/EnumValueCodec.java

Lines changed: 78 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,30 @@
11
package org.hswebframework.ezorm.rdb.codec;
22

33
import lombok.Getter;
4+
import org.hswebframework.ezorm.core.GlobalConfig;
45
import org.hswebframework.ezorm.core.ValueCodec;
6+
import org.hswebframework.ezorm.rdb.mapping.annotation.EnumCodec;
7+
import org.hswebframework.ezorm.rdb.utils.PropertyUtils;
58

69
import java.lang.reflect.Array;
710
import java.util.Arrays;
811
import java.util.List;
12+
import java.util.Objects;
913
import java.util.function.Function;
1014
import java.util.stream.Collector;
1115
import java.util.stream.Collectors;
1216
import java.util.stream.Stream;
1317

1418
public class EnumValueCodec implements ValueCodec<Object, Object> {
1519

20+
@SuppressWarnings("rawtypes")
1621
private static final Collector collector = Collectors.joining(",");
1722

1823
private static final Function<String, String[]> splitter = str -> str.split("[,]");
1924

25+
static final String PROPERTY_NAME = EnumCodec.NAME,
26+
PROPERTY_ORDINAL = EnumCodec.ORDINAL;
27+
2028
@SuppressWarnings("all")
2129
private final Class type;
2230
@SuppressWarnings("all")
@@ -28,7 +36,14 @@ public class EnumValueCodec implements ValueCodec<Object, Object> {
2836
@Getter
2937
private boolean toMask;
3038

39+
private final String property;
40+
3141
public EnumValueCodec(Class<?> type) {
42+
this(type, PROPERTY_NAME);
43+
}
44+
45+
public EnumValueCodec(Class<?> type, String property) {
46+
this.property = property;
3247
if (type.isArray()) {
3348
this.type = type.getComponentType();
3449
this.isArray = true;
@@ -41,11 +56,31 @@ public EnumValueCodec(Class<?> type) {
4156
}
4257
}
4358

59+
public EnumValueCodec(Class<?> type, String property, boolean toMask) {
60+
this(type, property);
61+
this.toMask = toMask;
62+
}
63+
4464
public EnumValueCodec(Class<?> type, boolean toMask) {
4565
this(type);
4666
this.toMask = toMask;
4767
}
4868

69+
private Object getValue(Enum<?> e) {
70+
switch (property) {
71+
case PROPERTY_NAME:
72+
return e.name();
73+
case PROPERTY_ORDINAL:
74+
return e.ordinal();
75+
default:
76+
return GlobalConfig
77+
.getPropertyOperator()
78+
.getProperty(e, property)
79+
.orElseThrow(() -> new IllegalArgumentException("no property [" + property + "] found in enum " + e.getDeclaringClass()));
80+
}
81+
82+
}
83+
4984
@Override
5085
@SuppressWarnings("all")
5186
public Object encode(Object value) {
@@ -57,17 +92,18 @@ public Object encode(Object value) {
5792

5893
if (value instanceof Enum) {
5994
if (!toMask) {
60-
return ((Enum) value).name();
95+
return getValue(((Enum) value));
6196
} else {
6297
return enumToMask(((Enum) value));
6398
}
6499
}
65100

66101
if (value instanceof Enum[]) {
67102
if (!toMask) {
68-
return Stream.of(((Enum[]) value))
69-
.map(Enum::name)
70-
.collect(collector);
103+
return Stream
104+
.of(((Enum[]) value))
105+
.map(this::getValue)
106+
.collect(collector);
71107
} else {
72108
return enumToMask(((Enum[]) value));
73109
}
@@ -77,53 +113,76 @@ public Object encode(Object value) {
77113
}
78114

79115
@Override
116+
@SuppressWarnings("rawtypes")
80117
public Object decode(Object data) {
118+
// 字符串
81119
if (data instanceof String) {
82120
if (!isArray) {
83121
for (Object value : values) {
84-
if (((Enum<?>) value).name().equalsIgnoreCase(String.valueOf(data))) {
122+
Enum<?> e = ((Enum<?>) value);
123+
if (eq(e, data)) {
85124
return value;
86125
}
87126
}
88127
return null;
89128
} else {
90129
List<String> arr = Arrays.asList(splitter.apply(((String) data)));
91130
return Stream
92-
.of(type.getEnumConstants())
93-
.map(Enum.class::cast)
94-
.filter(e -> arr.contains(e.name()))
95-
.toArray(l -> (Enum[]) Array.newInstance(type, l));
131+
.of(values)
132+
.map(Enum.class::cast)
133+
.filter(e -> arr.contains(String.valueOf(getValue(e))))
134+
.toArray(l -> (Enum[]) Array.newInstance(type, l));
96135
}
97136
}
98-
if (data instanceof Number) {
137+
// 数字类型 toMask
138+
if (data instanceof Number && toMask) {
99139
long val = ((Number) data).longValue();
100-
101140
Stream<Enum> stream = Stream
102-
.of(type.getEnumConstants())
103-
.map(Enum.class::cast)
104-
.filter(e -> toMask ? enumInMask(val, e) : e.ordinal() == val);
141+
.of(values)
142+
.map(Enum.class::cast)
143+
.filter(e -> enumInMask(val, e));
105144

106145
if (isArray) {
107-
return stream.toArray(l -> (Enum[]) Array.newInstance(type, l));
146+
return stream.toArray(l -> (Enum<?>[]) Array.newInstance(type, l));
108147
} else {
109148
return stream.findFirst().orElse(null);
110149
}
150+
}
111151

152+
Stream<Enum> stream = Stream
153+
.of(values)
154+
.map(Enum.class::cast)
155+
.filter(e -> eq(e, data));
156+
157+
if (isArray) {
158+
return stream.toArray(l -> (Enum<?>[]) Array.newInstance(type, l));
159+
} else {
160+
return stream.findFirst().orElse(null);
112161
}
113162

114-
return data;
115163
}
116164

117-
private boolean enumInMask(long mask, Enum e) {
165+
protected boolean eq(Enum<?> e, Object value) {
166+
Object val = getValue(e);
167+
// 忽略大小写对比字符串
168+
if (val instanceof String) {
169+
return ((String) val).equalsIgnoreCase(String.valueOf(value));
170+
}
171+
return GlobalConfig
172+
.getPropertyOperator()
173+
.compare(getValue(e), value) == 0;
174+
}
175+
176+
private boolean enumInMask(long mask, Enum<?> e) {
118177
return (mask & (1L << e.ordinal())) != 0;
119178
}
120179

121-
private long enumToMask(Enum... enums) {
180+
private long enumToMask(Enum<?>... enums) {
122181
if (enums == null) {
123182
return 0L;
124183
}
125184
long value = 0L;
126-
for (Enum e : enums) {
185+
for (Enum<?> e : enums) {
127186
value |= (1L << e.ordinal());
128187
}
129188
return value;

hsweb-easy-orm-rdb/src/main/java/org/hswebframework/ezorm/rdb/mapping/annotation/EnumCodec.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,24 @@
1212
@Codec
1313
public @interface EnumCodec {
1414

15+
String
16+
NAME = "name",
17+
ORDINAL = "ordinal";
18+
1519
/**
1620
* @return 是否使用将枚举的序号进行位掩码以实现多选
1721
* @see java.sql.JDBCType#NUMERIC
1822
* @see Long
1923
*/
2024
boolean toMask() default false;
2125

26+
/**
27+
* 使用指定的枚举属性作为数据库的值,默认{@link Enum#name()}
28+
*
29+
* @return value
30+
* @see Enum#name()
31+
* @see Enum#ordinal()
32+
*/
33+
String property() default NAME;
34+
2235
}

hsweb-easy-orm-rdb/src/main/java/org/hswebframework/ezorm/rdb/mapping/parser/DefaultValueCodecResolver.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public class DefaultValueCodecResolver implements ValueCodecResolver {
3535

3636
COMMONS.register(JsonCodec.class, (field, jsonCodec) -> JsonValueCodec.ofField(field.getField()));
3737

38-
COMMONS.register(EnumCodec.class, (field, jsonCodec) -> new EnumValueCodec(field.getPropertyType(), jsonCodec.toMask()));
38+
COMMONS.register(EnumCodec.class, (field, jsonCodec) -> new EnumValueCodec(field.getPropertyType(), jsonCodec.property(), jsonCodec.toMask()));
3939
COMMONS.register(Enumerated.class, (field, jsonCodec) -> new EnumValueCodec(field.getPropertyType(), jsonCodec.value()== EnumType.ORDINAL));
4040

4141
COMMONS.register(Date.class::isAssignableFrom, field -> new org.hswebframework.ezorm.rdb.codec.DateTimeCodec("yyyy-MM-dd HH:mm:dd", field.getPropertyType()));

hsweb-easy-orm-rdb/src/main/java/org/hswebframework/ezorm/rdb/supports/oracle/OracleDialect.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public OracleDialect() {
5050
registerDataType("longvarchar", DataType.builder(JdbcDataType.of(JDBCType.LONGVARCHAR, String.class), c -> "clob"));
5151

5252
registerDataType("varchar2", DataType.builder(DataType.jdbc(JDBCType.VARCHAR, String.class),
53-
column -> "varchar2(" + column.getLength() + " char)"));
53+
column -> "varchar2(" + column.getLength() + " char)"));
5454

5555
registerDataType("nvarchar2", DataType.builder(DataType.jdbc(JDBCType.VARCHAR, String.class),
5656
column -> "nvarchar2(" + column.getLength() + ")"));

hsweb-easy-orm-rdb/src/test/java/org/hswebframework/ezorm/rdb/codec/EnumValueCodecTest.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,31 @@ public void testMaskArray() {
4646

4747
EnumValueCodec codec = new EnumValueCodec(TestEnum[].class, true);
4848

49-
Assert.assertEquals(3L, codec.encode(new TestEnum[]{TestEnum.A,TestEnum.B}));
49+
Assert.assertEquals(3L, codec.encode(new TestEnum[]{TestEnum.A, TestEnum.B}));
5050

51-
Assert.assertArrayEquals(new TestEnum[]{TestEnum.A,TestEnum.B}, (Object[]) codec.decode(3));
51+
Assert.assertArrayEquals(new TestEnum[]{TestEnum.A, TestEnum.B}, (Object[]) codec.decode(3));
5252

5353
}
5454

55+
@Test
56+
public void testCustomProperty() {
57+
EnumValueCodec codec = new EnumValueCodec(TestEnum.class, "property",false);
58+
59+
for (TestEnum value : TestEnum.values()) {
60+
assertEquals(value, codec.decode(Long.valueOf(value.property).intValue()));
61+
}
62+
63+
}
5564

5665
public enum TestEnum {
5766
A, B, C;
67+
68+
final long property = ordinal() * 10;
69+
70+
public long getProperty() {
71+
return property;
72+
}
5873
}
5974

75+
6076
}

hsweb-easy-orm-rdb/src/test/java/org/hswebframework/ezorm/rdb/supports/oracle/OracleTableMetaParserTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,9 @@ public void testParse() {
136136

137137
Assert.assertNotNull(column);
138138

139-
Assert.assertEquals(column.getDataType(), "varchar2(32 char)");
140-
Assert.assertEquals(column.getType().getSqlType(), JDBCType.VARCHAR);
141-
Assert.assertEquals(column.getJavaType(), String.class);
139+
Assert.assertEquals("varchar2(32 char)", column.getDataType());
140+
Assert.assertEquals(JDBCType.VARCHAR, column.getType().getSqlType());
141+
Assert.assertEquals(String.class, column.getJavaType());
142142
Assert.assertTrue(column.isNotNull());
143143
// 这里只解析表结构,而不会解析键信息.
144144
// Assert.assertTrue(column.isPrimaryKey());

hsweb-easy-orm-rdb/src/test/resources/logback.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
</encoder>
1919
</appender>
2020

21-
<root level="debug">
21+
<root level="info">
2222

2323
<appender-ref ref="STDOUT"/>
2424
</root>

0 commit comments

Comments
 (0)