925 Commits

Author SHA1 Message Date
Redkale
bd21644571 Redkale 2.0.0.rc1 结束 2019-10-18 08:42:28 +08:00
Redkale
5f3599d9b8 2019-10-17 18:51:08 +08:00
Redkale
1e4a30bd70 2019-10-16 15:17:04 +08:00
Redkale
e7dc5de9f2 2019-10-15 22:18:44 +08:00
Redkale
ccb9cb28f5 修复JsonByteBufferWriter的utf8问题 2019-10-15 21:55:31 +08:00
Redkale
4d9b72c922 2019-10-15 21:43:45 +08:00
Redkale
a51ae13a39 2019-10-15 18:02:34 +08:00
Redkale
dfca186688 2019-10-15 18:01:34 +08:00
Redkale
fadd229a89 2019-10-14 15:29:28 +08:00
Redkale
7acc69adc4 2019-10-14 12:32:53 +08:00
Redkale
d88e4120a1 2019-10-13 17:29:12 +08:00
Redkale
ef98edd91a Convert.newConvert 增加第2个Function参数 2019-10-13 12:55:00 +08:00
Redkale
f4548bbe34 2019-10-11 11:13:41 +08:00
Redkale
11a5faca1d Utility增加reverseSort方法 2019-10-11 08:59:40 +08:00
Redkale
c37b0e8cb5 Redkale 2.0.0.beta5 结束 2019-10-10 09:21:48 +08:00
Redkale
a20570a6eb 2019-10-10 09:17:42 +08:00
Redkale
5e3edb7e1d 2019-10-09 13:43:11 +08:00
Redkale
ad8f1d2da6 增加util.ResourceInjectLoader功能 2019-10-09 13:42:29 +08:00
Redkale
24b23c894f 修复FileSimpledCoder的instance写错的bug 2019-10-09 13:41:39 +08:00
Redkale
c551d5fb81 2019-09-26 16:32:36 +08:00
Redkale
fba43894c1 2019-09-26 16:27:42 +08:00
Redkale
22cc7e086c RetResult增加Convert属性 2019-09-26 16:22:56 +08:00
Redkale
1791008729 2019-09-25 15:41:19 +08:00
Redkale
90e15dd253 2019-09-25 15:40:47 +08:00
Redkale
7db73c076c 2019-09-25 15:33:18 +08:00
Redkale
95ad6e99d9 2019-09-23 18:57:45 +08:00
Redkale
0b2a5d0f61 2019-09-23 08:59:03 +08:00
Redkale
b7acce0814 Redkale 2.0.0.beta4 结束 2019-09-20 08:58:51 +08:00
Redkale
8744e76cad 2019-09-19 21:52:52 +08:00
Redkale
446b3c13dc 2019-09-19 21:38:53 +08:00
Redkale
3951e28148 2019-09-19 21:38:22 +08:00
Redkale
b74d679608 修复ByteBuffer Utility.encodeUTF8的bug 2019-09-19 21:35:05 +08:00
Redkale
edbc878b73 修复Utility.encodeUTF8Length的bug 2019-09-19 21:22:47 +08:00
Redkale
f706209ec1 RestResult合并进HttpResult 2019-09-19 21:08:36 +08:00
Redkale
bf000b188f 增加RestResult功能 2019-09-19 20:30:30 +08:00
Redkale
def1736a9b 2019-09-19 13:22:56 +08:00
Redkale
0242f4c0c3 2019-09-19 13:22:20 +08:00
Redkale
5cd399b2df 2019-09-19 13:12:33 +08:00
Redkale
9ddb662016 Convert增加BiFunction<Attribute, Object, Object> fieldFunc参数 2019-09-19 12:05:03 +08:00
Redkale
2947275d54 2019-09-18 11:27:54 +08:00
Redkale
e43f814872 Utility增加containsMatch、removeMatch方法 2019-09-18 11:22:28 +08:00
Redkale
6e16f52e28 2019-09-18 11:02:13 +08:00
Redkale
fca13557df 【不兼容】删掉javax.persistence.GeneratedValue功能 2019-09-16 16:35:41 +08:00
Redkale
824a6df55a 2019-09-16 16:29:12 +08:00
Redkale
b98b526c50 2019-09-09 16:35:08 +08:00
Redkale
8f6aa4f4a5 2019-09-09 16:29:48 +08:00
Redkale
00a07a79b2 2019-09-09 16:25:10 +08:00
Redkale
264dfbef2e HttpServlet增加postStart方法 2019-09-04 10:00:29 +08:00
Redkale
2e27814809 2019-09-04 09:22:42 +08:00
Redkale
f767f40e56 StringConvertWrapper 改成 StringWrapper 2019-08-30 15:18:03 +08:00
Redkale
543ecc071a 2019-08-30 10:50:24 +08:00
Redkale
2a14f39495 2019-08-30 09:30:41 +08:00
Redkale
95c8ae2334 2019-08-30 08:05:28 +08:00
Redkale
338ea13828 2019-08-29 17:44:13 +08:00
Redkale
4a8b9e5fec 2019-08-29 16:43:45 +08:00
Redkale
e281cac3d3 2019-08-28 16:15:28 +08:00
Redkale
a495829a3c RestHeader支持InetSocketAddress类型 2019-08-28 14:31:33 +08:00
Redkale
b0deed2a89 WebSocket增加getSncpAddress方法,获取分布式下的sncp地址 2019-08-28 12:56:50 +08:00
Redkale
70a75abf74 Redkale 2.0.0.beta3 结束 2019-08-15 13:11:17 +08:00
Redkale
1aa97f8e79 2019-08-06 10:08:24 +08:00
Redkale
b4000235ac 2019-08-05 17:51:26 +08:00
Redkale
4b93f29a1c 2019-08-05 17:14:14 +08:00
Redkale
4892a50670 2019-08-05 16:26:52 +08:00
Redkale
2fe0ac0ef9 修复ColumnValue.mov时字段类型是long,而参数值是int会报错的bug 2019-07-31 17:19:35 +08:00
Redkale
333ae72148 2019-07-30 11:05:11 +08:00
Redkale
5fd5b7f303 2019-07-30 10:58:37 +08:00
Redkale
528cf45f3f ColumnExpress增加除法、取模表达式 2019-07-30 10:31:48 +08:00
Redkale
c7308e7320 修复ConvertFacotry.register方法中column参数没有对应field时会导致method的ignore失效的bug 2019-07-29 13:20:23 +08:00
Redkale
e2a49eaab7 2019-07-29 11:40:33 +08:00
Redkale
44bd6f235c 2019-07-25 16:58:20 +08:00
Redkale
601d15b513 2019-07-17 19:00:18 +08:00
Redkale
9e93485a97 新增HttpRequest.getQueryBytes方法 2019-07-17 18:42:45 +08:00
Redkale
ad87b2115d 修改多个@RetLabel不能正确根据locale获取对应值的bug 2019-07-17 15:14:48 +08:00
Redkale
27a587d31f 修复mysql下update操作值带转义字符导致失败的bug 2019-07-12 16:52:46 +08:00
Redkale
fc8fa27602 RetResult增加map静态方法 2019-07-11 14:53:51 +08:00
Redkale
f9aebc8ee3 修复同一个Entity类被多个source源分表分库操作时判断表是否已建有误的bug 2019-07-09 14:18:07 +08:00
Redkale
1167da8f4c Redkale 2.0.0.beta2 结束 2019-07-08 09:15:26 +08:00
Redkale
7a5fbcdccd 2019-07-03 11:35:37 +08:00
Redkale
345e929712 [不兼容修改]CacheSource的getCollectionMap序列方法增加一个set参数 2019-06-27 18:21:19 +08:00
Redkale
358862fe59 修复Entity类带boolean字段调DataSource.insert出现异常的bug 2019-06-26 16:51:48 +08:00
Redkale
3dde9bb293 2019-06-21 17:00:40 +08:00
Redkale
99ae4ccadd 从Context中移除BufferPool和ResponsePool 2019-06-20 15:26:20 +08:00
Redkale
98e9ffe0ef 2019-06-20 10:02:24 +08:00
Redkale
6927bfe8ac 2019-06-19 16:52:00 +08:00
Redkale
340a3a8fa3 2019-06-19 16:46:12 +08:00
Redkale
4724763991 2019-06-19 16:45:45 +08:00
Redkale
03353ad08c 2019-06-19 16:21:05 +08:00
Redkale
95c3354fcd WebSocketParam增加getAnnotations系列方法 2019-06-19 15:47:46 +08:00
Redkale
1bda2f92b9 HttpRequest增加getAnnotation系列方法 2019-06-18 22:59:07 +08:00
Redkale
bd3c706934 修复DataSource中json字段不为Serializable时会异常的bug 2019-06-13 22:34:53 +08:00
Redkale
ef3663aa36 修复DataSource中json字段不为Serializable时会异常的bug 2019-06-13 22:23:30 +08:00
Redkale
427ff717d4 UDP协议下bufferCapacity默认值为1350字节 2019-05-30 12:07:09 +08:00
Redkale
b409300412 UDP协议下bufferCapacity默认值为1480字节 2019-05-30 12:04:13 +08:00
Redkale
ca1f974dbe 2019-05-28 17:43:48 +08:00
Redkale
6a8c86096b DataSource的clearTable、dropTable在表不存在的情况下由抛异常改为结果值返回-1 2019-05-28 15:51:59 +08:00
Redkale
2b2fd9965b Redkale 2.0.0.beta1 结束 2019-05-25 10:46:10 +08:00
Redkale
0938635eb2 2019-05-18 08:37:53 +08:00
Redkale
a4a186751e 2019-05-01 08:05:37 +08:00
Redkale
ea5169b5c5 修改mysql中字符串带\会丢失的bug 2019-04-27 11:17:28 +08:00
Redkale
01bd195847 2019-04-26 21:24:02 +08:00
Redkale
a72c26a935 修复Utility.encodeUTF8和decodeUTF8 对4字节字符不能正常编码的bug 2019-04-22 12:24:55 +08:00
Redkale
a9900d9bfa 2019-04-19 19:41:04 +08:00
Redkale
6896401d2d 2019-04-19 19:32:24 +08:00
Redkale
886f01c9f3 DataSource在Cachable定时load时屏蔽log 2019-04-19 19:31:09 +08:00
Redkale
59c9251d70 2019-04-12 12:14:52 +08:00
Redkale
fad5f010d2 2019-04-12 11:57:21 +08:00
Redkale
737c4a92b9 修复ConvertFactory.registerIgnoreAll方法出现不生效的bug 2019-04-04 22:20:16 +08:00
Redkale
d3e8675948 Redkale 2.0.0.alpha2 开始 2019-04-04 22:18:49 +08:00
Redkale
a4ffc7a27c 2019-03-30 20:23:55 +08:00
Redkale
91bf7b1387 2019-03-30 17:28:25 +08:00
Redkale
1396296337 2019-03-29 11:51:19 +08:00
Redkale
e4672355fc Convert增加StringConvertWrapper功能 2019-03-29 11:44:37 +08:00
Redkale
129ed25ca4 2019-03-29 09:08:16 +08:00
Redkale
e6d7e5fe98 2019-03-28 17:36:31 +08:00
Redkale
73ce5fa11f Convert支持AbstractMap.SimpleEntry 2019-03-28 14:56:28 +08:00
Redkale
ce01c3d4ce 2019-03-22 12:21:38 +08:00
Redkale
3b3de316ea 2019-03-21 14:19:35 +08:00
Redkale
8c739ce54d 2019-03-16 12:58:54 +08:00
Redkale
0aa4d6c967 2019-03-15 10:19:00 +08:00
Redkale
d7a3f4d87d 2019-03-14 21:25:14 +08:00
Redkale
fe9e074581 2019-03-14 17:00:22 +08:00
Redkale
40813e8752 2019-03-14 16:17:43 +08:00
Redkale
e90f2e4142 WebSocket增加mergemsg属性功能 2019-03-14 15:27:05 +08:00
Redkale
2a19ea709b 2019-03-14 13:47:57 +08:00
Redkale
30c9be303f Convert增加ConvertMask[]参数方法 2019-03-14 13:17:31 +08:00
Redkale
e101b79472 修复ws数据包过大粘包的bug 2019-03-14 12:32:07 +08:00
Redkale
8ad919f952 修复了Convert在忽略子类某些字段时因为Method导致无法忽略父类的getter方法的bug 2019-03-06 09:31:18 +08:00
Redkale
294543c46e 取消DataSource兼容找不到unitName时使用第一个配置的功能 2019-03-05 20:16:57 +08:00
Redkale
79f8363d47 2019-03-05 12:23:21 +08:00
Redkale
6d3553b0b5 2019-02-12 13:16:43 +08:00
Redkale
403ab4e281 2019-02-12 12:23:03 +08:00
Redkale
87e7c43032 修复JDK9+以上RedkaleClassLoader的getAllURLS方法中的BUG 2019-02-12 11:52:23 +08:00
Redkale
a321b41699 2019-01-19 16:28:44 +08:00
Redkale
fea34863e3 2019-01-18 22:25:20 +08:00
Redkale
bcaf7ab73e 2019-01-18 19:48:32 +08:00
Redkale
b9d7eaee1b 2019-01-18 18:52:47 +08:00
Redkale
d605045858 2019-01-18 16:55:48 +08:00
Redkale
cf2ab617c2 修复AioAsyncConnection关闭时write队列还有数据没写完的bug 2019-01-18 15:50:23 +08:00
Redkale
204514cb08 增加Utility.nowMillis方法 2019-01-18 10:41:30 +08:00
Redkale
cfe01cca75 2019-01-16 19:04:54 +08:00
Redkale
ac294c58ae 2019-01-16 19:01:48 +08:00
Redkale
6950eb2f30 2019-01-13 16:51:06 +08:00
Redkale
847f81374b 2019-01-12 11:44:50 +08:00
Redkale
bb09aea8bb 2019-01-12 11:28:29 +08:00
Redkale
2e1ff333f5 Application.singleton多加一个参数,指定其他Service也被加载 2019-01-12 11:16:27 +08:00
Redkale
c14a2b4011 updateColumnCompose 2019-01-12 11:15:02 +08:00
Redkale
d9c6c3d2d0 2019-01-11 16:51:21 +08:00
Redkale
91d4477ed9 DataSource增加字段加解密功能,主类:CryptColumn/CryptHandler 2019-01-11 16:41:14 +08:00
Redkale
623c0a127e Attribute增加attach方法 2019-01-11 15:22:29 +08:00
Redkale
bc64666700 Reproduce.create方法中BiPredicate参数的第一个泛型改为AccessibleObject 2019-01-10 18:43:45 +08:00
Redkale
5c7dd7d782 2019-01-09 16:17:48 +08:00
Redkale
e78a2da6c0 2019-01-09 16:16:08 +08:00
Redkale
065be6f3d7 增加RetResult.success(V result)方法 2019-01-09 09:44:53 +08:00
Redkale
874f3330b8 Update README.md 2019-01-08 14:33:41 +08:00
Redkale
684edfa10b 2019-01-08 12:54:09 +08:00
Redkale
e69a120965 2019-01-08 12:46:20 +08:00
Redkale
4a36244294 2019-01-08 12:39:21 +08:00
Redkale
cb444be0f7 优化Application.singleton方法 2019-01-08 12:32:47 +08:00
Redkale
8b5cbf186f 2019-01-08 09:13:05 +08:00
Redkale
dbc6f8a196 2019-01-07 21:38:44 +08:00
Redkale
9b94604166 2019-01-07 21:17:20 +08:00
Redkale
cc98a85711 2019-01-07 21:09:22 +08:00
Redkale
6855d06f55 JsonConvert增加不带Type参数的convertTo方法 2019-01-07 20:07:36 +08:00
Redkale
89d90ddf5b 修复getHttpContent会变成POST请求的bug 2019-01-07 17:05:02 +08:00
Redkale
6280111121 2019-01-05 09:42:03 +08:00
Redkale
231d41c15f DataSource增加清空表clear和删除表drop的系列方法 2019-01-04 14:26:20 +08:00
Redkale
cfca7adc66 2019-01-03 18:38:07 +08:00
Redkale
aedd215de4 2019-01-03 18:33:49 +08:00
Redkale
df8e839580 优化WebSocket给多个userid发消息的实现 2019-01-03 09:35:28 +08:00
Redkale
300441b9f7 DataSource增加getCollectionMap系列接口 2019-01-03 09:33:19 +08:00
Redkale
1a5e9022ae Convert支持java.time.Duration 2019-01-03 09:07:26 +08:00
Redkale
2a3b8f87d3 兼容@Resource标记在泛型类型字段上 2019-01-03 09:06:08 +08:00
Redkale
b7930f1ed7 Redkale 2.0.0 开始 2019-01-03 09:05:00 +08:00
Redkale
a78c2145e6 2018-12-24 17:16:39 +08:00
Redkale
ee20a34a70 2018-12-24 14:52:05 +08:00
Redkale
33bd80c572 2018-12-22 15:16:00 +08:00
Redkale
031309b105 2018-12-22 15:08:56 +08:00
Redkale
bcbd981a9b 2018-12-21 10:55:20 +08:00
Redkale
b7ce390c33 WebServlet.value带.不视为正则表达式 2018-12-21 10:38:37 +08:00
Redkale
c9d099c694 2018-12-20 17:22:16 +08:00
Redkale
fcca0329c6 2018-12-20 13:55:46 +08:00
Redkale
c82c0bc680 2018-12-20 11:51:12 +08:00
Redkale
2921478a0a 2018-12-20 11:38:11 +08:00
Redkale
61a5420d48 兼容泛型嵌套 2018-12-19 18:38:28 +08:00
Redkale
702ab6ef6e 2018-12-19 16:03:11 +08:00
Redkale
2576e71a7d 2018-12-19 11:33:08 +08:00
Redkale
0d0bd78213 2018-12-18 15:20:13 +08:00
Redkale
8d9fa8f9cf 2018-12-18 14:15:27 +08:00
Redkale
25eaf6e353 AsyncConnection接口大变动 2018-12-18 14:04:49 +08:00
Redkale
8afcaa0b34 2018-12-18 09:41:20 +08:00
Redkale
1824f8150c 2018-12-17 10:57:49 +08:00
Redkale
2f89778fd6 2018-12-17 10:56:00 +08:00
Redkale
f9d250b43c 2018-12-17 10:29:23 +08:00
Redkale
3a3c09d8aa 2018-12-15 15:07:46 +08:00
Redkale
09a0d4f9e2 2018-12-15 15:06:24 +08:00
Redkale
3bba781183 WATCH服务增加功能:更改Server的监听地址和端口 2018-12-13 13:47:44 +08:00
Redkale
6426f8fe91 2018-12-11 19:46:31 +08:00
Redkale
5906594148 2018-12-11 18:58:15 +08:00
Redkale
1b188c863c 2018-12-10 19:51:31 +08:00
Redkale
087b4cb571 2018-12-10 19:47:26 +08:00
Redkale
c9496b6231 application.xml中source节点兼容DataJdbcSource 2018-12-10 19:44:56 +08:00
Redkale
60d95d7628 2018-12-06 21:29:55 +08:00
Redkale
dd9e7e77b5 2018-12-06 21:06:21 +08:00
Redkale
50c9363876 2018-12-05 17:59:56 +08:00
Redkale
938e357745 2018-12-03 09:04:27 +08:00
Redkale
08ee51f8ab 2018-12-01 14:22:30 +08:00
Redkale
40ae555645 2018-11-29 14:09:18 +08:00
Redkale
33f89264a6 2018-11-29 13:54:14 +08:00
Redkale
e4ea20cc5f 2018-11-28 14:33:55 +08:00
Redkale
045b7db1af 修复JsonConvert的""空字符串转换对象抛异常的BUG 2018-11-28 14:23:10 +08:00
Redkale
676c1b5d21 修复JsonConvert的""空字符串转换对象抛异常的BUG 2018-11-28 14:22:00 +08:00
Redkale
e4319246b8 2018-11-28 14:04:07 +08:00
Redkale
32d8515bf4 DataSource增加部分JSON功能 2018-11-28 11:17:55 +08:00
Redkale
d7e7113201 Sncp的部分Attribute.type()改为genericType方法 2018-11-28 09:18:12 +08:00
Redkale
9493aa43a7 Attribute增加genericType方法 2018-11-28 09:12:58 +08:00
Redkale
d07c55b831 【不兼容】BSON格式升级,兼容子类数据转父类对象 2018-11-27 15:10:19 +08:00
Redkale
47dab88d72 调整Convert部分内部接口 2018-11-27 14:10:58 +08:00
Redkale
9e553aeff6 修复JsonReader.readSmallString() BUG 2018-11-27 11:48:50 +08:00
Redkale
ed8e754557 兼容ColumnValue...含null的情况 2018-11-24 14:20:06 +08:00
Redkale
651dc3df2a 还原 2018-11-22 14:47:58 +08:00
Redkale
84e5bc3437 2018-11-22 14:46:55 +08:00
Redkale
64fd0176ac 兼容手动new XXXService字段inject时抛异常 2018-11-22 14:45:24 +08:00
Redkale
c1f3115d4e 2018-11-20 10:55:09 +08:00
Redkale
1c70834760 2018-11-19 17:33:33 +08:00
Redkale
7c901731bc Bson的skipValue方法支持部分常规Collection<JavaBean>、Map<String, JavaBean>字段类型 2018-11-19 15:32:24 +08:00
Redkale
2b2d53e515 Bson的skipValue方法支持部分常规Collection、Map字段类型 2018-11-19 15:14:48 +08:00
Redkale
be051ecf45 Redkale 1.9.9 开始 2018-11-19 15:12:20 +08:00
Redkale
18534eb654 2018-11-08 16:08:48 +08:00
Redkale
a5a926fd94 FilterNode、FilterJoinNode增加copy方法 2018-10-18 14:47:07 +08:00
Redkale
0cb9f2cad3 2018-10-17 08:18:23 +08:00
Redkale
98209cc82e 修改WebSocketNode.existsWebSocket的实现 2018-10-10 14:03:54 +08:00
Redkale
1879afa6a4 2018-10-09 16:34:35 +08:00
Redkale
4a6404dfec 2018-09-27 09:54:42 +08:00
Redkale
0fa1c4a08f 修复WebSocket中Connection重复的bug 2018-09-27 09:51:44 +08:00
Redkale
573d7c5776 修复Rest.createRestWebSocketServlet空指针bug 2018-09-26 17:23:19 +08:00
Redkale
c56c9bf260 Redkale 1.9.8 开始 2018-09-26 17:21:33 +08:00
Redkale
387865789f 2018-09-20 16:03:33 +08:00
Redkale
03fcf43a89 2018-09-19 11:11:59 +08:00
Redkale
df8090813a 2018-09-12 12:11:19 +08:00
Redkale
849b29d00f CacheSource的增删改查操作增加Type参数 2018-09-12 12:04:59 +08:00
Redkale
4b7f65e1c4 2018-09-11 14:29:42 +08:00
Redkale
4545d81e50 2018-09-11 11:12:43 +08:00
Redkale
1ac5f060a4 增加WebSocketAction功能 2018-09-11 09:13:19 +08:00
Redkale
7e1ff8e315 2018-09-10 17:23:23 +08:00
Redkale
4e0c1fee97 2018-09-10 14:02:26 +08:00
Redkale
0b38f23f2d 2018-09-10 14:01:56 +08:00
Redkale
98ea6861c1 2018-09-10 10:44:03 +08:00
Redkale
c07b628ea1 FilterNode增加readonly属性 2018-09-07 10:21:48 +08:00
Redkale
b1b979c0b5 优化Rest.createRestServlet减少preInit的耗时 2018-09-07 09:20:52 +08:00
Redkale
35b708b01d 2018-09-07 08:50:20 +08:00
Redkale
229ae0d44f 2018-09-06 18:17:11 +08:00
Redkale
7d6897fa36 2018-09-06 14:33:53 +08:00
Redkale
5851093590 2018-09-05 16:58:19 +08:00
Redkale
4646c1d1f0 2018-09-05 16:57:09 +08:00
Redkale
f3763dbf72 2018-09-05 16:41:44 +08:00
Redkale
6a8c60ec78 优化NodeHttpServer.loadRestServlet 2018-09-05 16:15:21 +08:00
Redkale
ae437fd5d6 优化Rest.createRestServlet 2018-09-05 15:53:54 +08:00
Redkale
7251c984c8 修复FilterNode.findValue的bug 2018-09-05 11:00:47 +08:00
Redkale
ec449220eb 2018-09-05 09:49:20 +08:00
Redkale
78265944f0 2018-09-05 09:23:41 +08:00
Redkale
d2791f6d1b 2018-09-05 08:29:58 +08:00
Redkale
d525d2664b 2018-08-31 10:39:43 +08:00
Redkale
a4ccea91ad 修复FilterJoinNode.any方法bug 2018-08-29 16:06:41 +08:00
Redkale
750da161eb 增强HttpUserType的类型校验 2018-08-28 10:18:27 +08:00
Redkale
ac50312f0b 2018-08-27 18:28:56 +08:00
Redkale
8d44d48072 2018-08-27 18:26:16 +08:00
Redkale
6c2baa1708 增加RestConvertCoder功能 2018-08-27 18:25:08 +08:00
Redkale
4525cfe594 2018-08-27 12:36:35 +08:00
Redkale
921f96c975 优化toBuffers方法 2018-08-27 12:29:59 +08:00
Redkale
29ce57d3af BsonWriter.toBuffers存在并发问题 2018-08-27 12:07:45 +08:00
Redkale
2ca1e6305c 修改HttpResponse.finish(byte[]) 2018-08-27 11:55:36 +08:00
Redkale
827b404a57 Update application.xml 2018-08-25 13:35:48 +08:00
Redkale
83569142c1 2018-08-25 13:12:24 +08:00
Redkale
2da0faacc3 2018-08-24 16:24:58 +08:00
Redkale
cf51bee2cc 2018-08-24 16:07:19 +08:00
Redkale
0dd55dc947 2018-08-24 16:04:49 +08:00
Redkale
620fa0430c ClassFilter输出更详细日志 2018-08-23 19:54:47 +08:00
Redkale
d053590257 增加JDK9+环境下显示进程PID功能 2018-08-23 19:28:20 +08:00
Redkale
684af3de61 application.xml的properties值支持${APP_HOME} 2018-08-23 09:59:14 +08:00
Redkale
6c6e26ed0b 2018-08-22 10:37:49 +08:00
Redkale
4a05bfbd08 2018-08-22 10:34:48 +08:00
Redkale
787dc7b32f 2018-08-22 10:03:20 +08:00
Redkale
85a1f99f6e 2018-08-22 09:42:51 +08:00
Redkale
4fe8a1199e 修复CollectionDecoder的creator指定错误的bug 2018-08-22 09:30:11 +08:00
Redkale
7312dbc4c5 增加H2数据库的支持 2018-08-21 10:06:05 +08:00
Redkale
cfecfabc92 createRestServlet兼容throws IOException和RuntimeException的子类 2018-08-20 17:28:34 +08:00
Redkale
587160c5fe Redkale 1.9.7 开始 2018-08-20 17:23:13 +08:00
Redkale
ee7fe3ed33 2018-08-20 16:49:39 +08:00
Redkale
47d4a6cc29 2018-08-20 14:42:16 +08:00
Redkale
c1e4763369 2018-08-20 14:28:02 +08:00
Redkale
333ba0f162 2018-08-18 11:27:50 +08:00
Redkale
e039b0e9f6 2018-08-17 11:26:45 +08:00
Redkale
b3c5e3beca 2018-08-15 18:18:27 +08:00
Redkale
70ba45c3bd 2018-08-15 18:13:09 +08:00
Redkale
14ae44fcac 修复DataJdbcSource.queryList会查total的BUG 2018-08-15 16:57:44 +08:00
Redkale
f7618f5da4 DataSqlSource.directQuery接口变动 2018-08-15 14:49:20 +08:00
Redkale
d6c6e4c02e 2018-08-14 10:40:11 +08:00
Redkale
9365052b85 2018-08-13 19:20:21 +08:00
Redkale
ef88063094 修复EntityCache重复insert数据时会导致map和list的同一id的对象不一致的BUG 2018-08-13 19:12:05 +08:00
Redkale
4cbaf85eea 2018-08-13 18:30:07 +08:00
Redkale
6c07123da3 2018-08-13 18:29:12 +08:00
Redkale
04a4ce12c7 2018-08-09 19:32:03 +08:00
Redkale
e00ed8ae37 增加DataMemorySource 2018-08-08 14:30:51 +08:00
Redkale
218a79b60a 2018-08-07 15:41:22 +08:00
Redkale
19ae86c71f 2018-08-07 13:52:00 +08:00
Redkale
9250d4e64d 2018-08-07 11:53:26 +08:00
Redkale
9f5aa58a31 2018-08-06 19:58:19 +08:00
Redkale
c8b0a88573 2018-08-06 18:05:13 +08:00
Redkale
7cf3f49aa1 1.9.5.1 2018-08-06 17:39:17 +08:00
Redkale
be2c803f82 2018-08-06 17:38:03 +08:00
Redkale
fd1197e8dc 2018-08-04 23:40:52 +08:00
Redkale
115f91b64a 2018-08-04 18:31:29 +08:00
Redkale
dfb800473a 2018-08-04 18:08:11 +08:00
Redkale
c69c1bb134 ppl 2018-08-04 15:12:22 +08:00
Redkale
5b501c7c2f 2018-08-04 14:52:44 +08:00
Redkale
8d5ce56ec2 FileHandler.limit支持G/M/K 2018-08-03 22:23:56 +08:00
Redkale
15c97ddc18 2018-08-02 13:51:41 +08:00
Redkale
36d7fbf4e9 2018-07-31 15:47:18 +08:00
Redkale
919e7aa5c6 2018-07-30 16:02:26 +08:00
Redkale
2174de2b71 2018-07-30 16:01:39 +08:00
Redkale
cb9e914e44 2018-07-30 15:51:20 +08:00
Redkale
15f856b762 2018-07-30 15:26:47 +08:00
Redkale
991dba0d62 2018-07-27 21:29:50 +08:00
Redkale
aa2685d6e4 修复WebSocketEngine的future = future.whenComplete问题 2018-07-27 20:35:48 +08:00
Redkale
0952150328 2018-07-27 20:29:13 +08:00
Redkale
e6ef4d1546 2018-07-27 20:02:08 +08:00
Redkale
16cf85abb9 2018-07-27 19:59:58 +08:00
Redkale
5afe0ead94 修复WebSocketNode远程模式下forceCloseWebSocket会报错的BUG 2018-07-27 19:52:12 +08:00
Redkale
b6c933f989 WebSocketNode远程模式下forceCloseWebSocket会报错 2018-07-27 19:38:46 +08:00
Redkale
feaf1a1f06 Redkale 1.9.6 开始 2018-07-27 19:19:00 +08:00
Redkale
6b54c6e886 2018-07-26 16:16:09 +08:00
Redkale
a95b69ab79 2018-07-26 11:54:09 +08:00
Redkale
a2492ae248 2018-07-26 11:36:51 +08:00
Redkale
0db1c4413c 2018-07-26 10:53:35 +08:00
Redkale
8718bca6e8 2018-07-26 08:48:23 +08:00
Redkale
6486863d00 2018-07-25 16:36:09 +08:00
Redkale
bfc2397dbf 2018-07-25 14:58:02 +08:00
Redkale
0cfdb9795b 2018-07-25 12:06:11 +08:00
Redkale
d327757d59 2018-07-25 11:43:51 +08:00
Redkale
e88c4fa2e3 修复进程关闭时WebSocket没有执行onClose方法的BUG 2018-07-24 20:11:02 +08:00
Redkale
69a0071e17 2018-07-23 10:06:36 +08:00
Redkale
d3cfe809e7 2018-07-23 09:38:47 +08:00
Redkale
0ca6e5401a 2018-07-23 09:37:49 +08:00
Redkale
8ff2b60ed4 2018-07-22 18:37:07 +08:00
Redkale
1dbe125e27 2018-07-22 18:15:24 +08:00
Redkale
32a595262d 2018-07-22 18:03:30 +08:00
Redkale
01431a93a4 2018-07-22 17:55:02 +08:00
Redkale
00a12d8113 2018-07-21 14:21:50 +08:00
Redkale
0f2474386c 2018-07-21 10:58:17 +08:00
Redkale
5de52ed6e8 Convert优化 2018-07-21 10:50:01 +08:00
Redkale
099b3fb7f3 2018-07-20 15:00:18 +08:00
Redkale
ed85e33403 2018-07-20 11:38:53 +08:00
Redkale
daff7d095f 2018-07-20 10:58:51 +08:00
Redkale
a8ff82229f 2018-07-20 10:01:59 +08:00
Redkale
2874e7d195 2018-07-20 09:48:47 +08:00
Redkale
8baea2657d 2018-07-20 09:04:05 +08:00
Redkale
03e9a5cbcb 更新Convert的Array、Map相关接口 2018-07-19 10:26:40 +08:00
Redkale
8d2f2a28af 2018-07-18 16:14:09 +08:00
Redkale
4a4bade180 Decoder/Encoder获取更多信息 2018-07-16 19:16:10 +08:00
Redkale
28e72f9883 Convert增加readByteArray和writeByteArray方法 2018-07-16 18:38:02 +08:00
Redkale
681e3967d2 2018-07-16 14:02:30 +08:00
Redkale
640dcbc8d7 2018-07-16 12:40:32 +08:00
Redkale
19276ecb91 2018-07-16 00:36:45 +08:00
Redkale
9f9078cdc5 2018-07-16 00:33:45 +08:00
Redkale
9bd1e0c97b 2018-07-15 23:42:28 +08:00
Redkale
c2c8f700a2 2018-07-15 22:18:52 +08:00
Redkale
86895eb5ef 2018-07-15 20:10:09 +08:00
Redkale
e8dacd6b70 2018-07-15 18:11:30 +08:00
Redkale
03fcf1dc95 2018-07-15 17:43:58 +08:00
Redkale
953b2be224 2018-07-14 12:54:48 +08:00
Redkale
55645ba2a0 2018-07-14 09:22:42 +08:00
Redkale
858c6a0aaf 2018-07-14 00:14:10 +08:00
Redkale
85d4023fa2 2018-07-13 23:22:02 +08:00
Redkale
607fc8e45f 2018-07-13 23:13:42 +08:00
Redkale
511a966ce5 2018-07-13 23:11:36 +08:00
Redkale
6d135efbc6 2018-07-13 22:56:33 +08:00
Redkale
5dff6310aa 2018-07-13 11:52:28 +08:00
Redkale
194a06c748 2018-07-13 09:41:26 +08:00
Redkale
1ce97aa20d 2018-07-13 06:46:55 +08:00
Redkale
1c88fb0355 修复JsonConvert没有按指定Type进行convertTo的BUG 2018-07-12 17:45:41 +08:00
Redkale
7b81c42377 JsonConvert支持带空格的数值字符串转成Number对象 2018-07-12 14:19:40 +08:00
Redkale
1afa38a947 2018-07-11 16:58:03 +08:00
Redkale
eedb418299 增加RpcRemoteException 2018-07-11 16:15:24 +08:00
Redkale
9efc14e627 2018-07-10 15:36:23 +08:00
Redkale
0dc3d65307 去掉对Rest中find、delete开头方法的特殊处理 2018-07-10 15:25:40 +08:00
Redkale
e3ddbe609c 2018-07-09 11:10:15 +08:00
Redkale
f115934499 2018-07-08 14:49:48 +08:00
Redkale
f5e290a47a Watch组件增加可以获取指定Servie中某个可序列化的字段的值 2018-07-06 22:28:20 +08:00
Redkale
29cd395888 RestConvert增加可以返回skipAllIgnore(true)的Convert功能 2018-07-06 18:53:39 +08:00
Redkale
9ca7855756 2018-07-05 11:47:58 +08:00
Redkale
1f1ab112eb 2018-07-05 11:36:30 +08:00
Redkale
b172b66263 去掉persistence.xml的监听文件变化功能,该有watch组件提供动态修改数据源配置 2018-07-05 09:49:19 +08:00
Redkale
b08f9f5757 增加java.util.Properties的convert 2018-07-05 09:47:39 +08:00
Redkale
32e65ff304 2018-07-03 15:49:32 +08:00
Redkale
40126c923e 2018-07-03 15:09:40 +08:00
Redkale
83ae5b0a13 2018-07-03 15:05:54 +08:00
Redkale
aea6a2839d 增加LogExcludeLevel功能 2018-07-03 10:10:52 +08:00
Redkale
6211d9ff18 Redkale 1.9.5 开始 2018-07-03 09:28:17 +08:00
Redkale
0e7fab71b8 2018-06-28 09:01:33 +08:00
Redkale
a106c8ed60 2018-06-26 16:35:12 +08:00
Redkale
ae52d0ab3d 2018-06-26 16:30:47 +08:00
Redkale
c993cd5b5a Json.writeChar以'A'形式输出 2018-06-25 19:38:32 +08:00
Redkale
9bdd83cc6e 2018-06-25 18:46:53 +08:00
Redkale
1b6a23c1a9 增加APP_CONF配置项,在启动脚本中可以指定配置目录 2018-06-22 16:38:24 +08:00
Redkale
2703d94b83 修复Convert中泛型与非泛型类型并存的问题 2018-06-20 15:58:10 +08:00
Redkale
4cb51ecbe6 2018-06-20 15:48:08 +08:00
Redkale
0cf64121ae 2018-06-12 16:52:09 +08:00
Redkale
58eb3c5d64 AsyncConnection.write调整 2018-06-12 09:15:32 +08:00
Redkale
3c645b4c7f 修复Rest部分情况下获取不到参数的BUG 2018-06-09 10:15:49 +08:00
Redkale
a540eed0ed Redkale 1.9.4 开始 2018-06-09 09:48:50 +08:00
Redkale
ad567b4c40 2018-06-04 18:04:27 +08:00
Redkale
6f8aeea870 2018-06-04 17:59:21 +08:00
Redkale
87a1a7c641 2018-06-04 09:39:46 +08:00
Redkale
178f96a3b5 2018-06-04 08:24:48 +08:00
Redkale
cc629a1a7c 2018-06-02 22:47:13 +08:00
Redkale
1cb72df52e 2018-06-02 22:34:34 +08:00
Redkale
4c32422493 RestWebSocket增加wsthreads属性配置 2018-06-02 15:49:10 +08:00
Redkale
7361823ece 2018-06-02 09:17:34 +08:00
Redkale
03824a900c 2018-06-01 18:35:56 +08:00
Redkale
c40913d690 2018-06-01 12:13:05 +08:00
Redkale
bdfdf153f7 2018-06-01 10:31:00 +08:00
Redkale
fa9e62d2a7 2018-06-01 10:00:59 +08:00
Redkale
bcca20dbbb 2018-05-31 17:12:18 +08:00
Redkale
bca42ee7b4 2018-05-31 15:21:48 +08:00
Redkale
d5f2bae47c 2018-05-31 15:15:08 +08:00
Redkale
fe1e99c67c 2018-05-31 11:34:50 +08:00
Redkale
699d55d70e 2018-05-31 10:23:16 +08:00
Redkale
3d11a95a29 2018-05-31 09:13:15 +08:00
Redkale
a983c53189 2018-05-31 09:02:55 +08:00
Redkale
0ee28f59ce 2018-05-31 08:47:49 +08:00
Redkale
96ee0584b8 2018-05-30 19:48:17 +08:00
Redkale
7352d5b8ed 2018-05-30 19:47:21 +08:00
Redkale
e79fdd887c 2018-05-30 19:43:46 +08:00
Redkale
7b5b0f34ff 2018-05-30 18:54:02 +08:00
Redkale
ae8fb992fb 2018-05-30 18:48:52 +08:00
Redkale
d5409518ed 2018-05-30 18:45:01 +08:00
Redkale
6bb2e152a5 2018-05-30 18:23:12 +08:00
Redkale
c73ebf88db 2018-05-29 09:35:15 +08:00
Redkale
bfdceec81b 2018-05-29 09:31:03 +08:00
Redkale
dd444e3a0f 2018-05-28 22:13:50 +08:00
Redkale
79de8dbbca 2018-05-28 17:38:41 +08:00
Redkale
5c6f3c3712 2018-05-28 17:27:10 +08:00
Redkale
0d0663a7de 2018-05-28 17:19:06 +08:00
Redkale
6d1c4e6c85 2018-05-28 10:10:59 +08:00
Redkale
f539633497 2018-05-28 10:01:17 +08:00
Redkale
d9ddd6d772 2018-05-28 09:59:39 +08:00
Redkale
4a2ba4e914 2018-05-26 09:58:34 +08:00
Redkale
cc864e3e69 2018-05-25 15:31:43 +08:00
Redkale
4cd5bd37d3 2018-05-24 10:09:35 +08:00
Redkale
ff14e675fa 2018-05-23 18:20:30 +08:00
Redkale
a46cb462a2 2018-05-23 09:28:33 +08:00
Redkale
8077dedd03 2018-05-22 09:50:38 +08:00
Redkale
6a707dff0c 2018-05-21 14:38:07 +08:00
Redkale
c9aa31d803 2018-05-21 13:57:25 +08:00
Redkale
4494683db2 2018-05-21 12:04:15 +08:00
Redkale
f440b2d639 2018-05-21 11:54:52 +08:00
Redkale
324d4bd94e 2018-05-20 13:14:41 +08:00
Redkale
bb82d70f5a 2018-05-20 12:34:53 +08:00
Redkale
8d1022f70f 2018-05-19 14:58:31 +08:00
Redkale
00034981ef 2018-05-19 13:07:36 +08:00
Redkale
2b3b33979c 2018-05-19 11:34:31 +08:00
Redkale
8e0788ccf3 2018-05-19 10:51:30 +08:00
Redkale
6e81541a3b 2018-05-19 10:19:41 +08:00
Redkale
6acb17da7c 2018-05-18 17:41:51 +08:00
Redkale
774286952b 2018-05-18 15:20:37 +08:00
Redkale
35a3c81391 2018-05-18 15:11:18 +08:00
Redkale
90d28eb4f4 2018-05-18 14:58:13 +08:00
Redkale
aab24fdbbe 2018-05-18 12:29:07 +08:00
Redkale
d0c24ed7a7 2018-05-18 12:25:49 +08:00
Redkale
2260906396 2018-05-17 19:51:02 +08:00
Redkale
0901195147 2018-05-17 19:49:27 +08:00
Redkale
c11a8e7bd9 2018-05-17 19:48:48 +08:00
Redkale
8176ec1b0a 2018-05-17 19:42:34 +08:00
Redkale
8f598fe4eb 2018-05-17 17:58:23 +08:00
Redkale
2fac5c853e 2018-05-17 17:46:32 +08:00
Redkale
4dbd6b57f8 2018-05-17 17:41:52 +08:00
Redkale
a5f21a99d8 2018-05-17 17:35:47 +08:00
Redkale
6f98b44471 2018-05-17 17:20:08 +08:00
Redkale
b13b07fb05 2018-05-17 17:06:57 +08:00
Redkale
1f8884a415 2018-05-12 15:46:33 +08:00
Redkale
848a30b2db 2018-05-12 14:35:34 +08:00
Redkale
350ece1533 2018-05-12 14:24:59 +08:00
Redkale
513183f55c 2018-05-11 17:38:11 +08:00
Redkale
b23434e3bb 2018-05-11 16:22:51 +08:00
Redkale
7084fb2ea2 2018-05-11 08:18:50 +08:00
Redkale
5becdf4d50 切换DataJdbcSource 2018-05-10 19:44:51 +08:00
Redkale
5aa10e9d74 切换DataJdbcSource 2018-05-10 19:39:47 +08:00
Redkale
db462ec134 2018-05-10 19:39:00 +08:00
Redkale
75e9f6162b 2018-05-10 19:22:35 +08:00
Redkale
970d530fbd 2018-05-10 10:25:33 +08:00
Redkale
13ffa2a3e5 2018-05-09 16:19:00 +08:00
Redkale
8416826827 2018-05-09 15:53:34 +08:00
Redkale
0a296ee857 2018-05-09 09:23:43 +08:00
Redkale
bb45470078 2018-05-07 17:03:39 +08:00
Redkale
d3c6ab8dc5 2018-05-07 12:44:55 +08:00
Redkale
0bf34781c5 2018-05-07 11:46:05 +08:00
Redkale
20940e82de 2018-05-06 18:23:38 +08:00
Redkale
78df572bec 2018-05-06 18:20:23 +08:00
Redkale
ffd0bec5c6 2018-05-06 16:54:46 +08:00
Redkale
62783d0765 2018-05-06 16:38:41 +08:00
Redkale
7116f33a3a 2018-05-06 07:50:50 +08:00
Redkale
a168dab8c0 2018-05-05 16:05:48 +08:00
Redkale
e3e065f36e 2018-05-05 13:23:42 +08:00
Redkale
d282321d98 2018-05-05 11:43:32 +08:00
Redkale
1abdb3b874 2018-05-05 11:22:26 +08:00
Redkale
1807287321 2018-05-05 10:29:55 +08:00
Redkale
a29652180b 2018-05-05 06:21:23 +08:00
Redkale
d4a85ac136 2018-05-04 21:03:40 +08:00
Redkale
007f635081 2018-05-04 20:30:54 +08:00
Redkale
f75e15a375 2018-05-04 20:29:40 +08:00
Redkale
508c7c4c0a 2018-05-04 20:23:08 +08:00
Redkale
7166dc0ec0 2018-05-04 17:31:45 +08:00
Redkale
1f28b7e803 2018-05-04 15:26:07 +08:00
Redkale
5d77139965 2018-05-04 15:17:59 +08:00
Redkale
126dab08b2 2018-05-04 12:53:16 +08:00
Redkale
a8175d9e19 2018-05-04 11:18:46 +08:00
Redkale
a5c11b5119 2018-05-04 10:26:44 +08:00
Redkale
bfc6b04a30 2018-05-04 08:50:17 +08:00
Redkale
a5dd878c66 2018-05-03 21:15:48 +08:00
Redkale
ed7ce80565 2018-05-03 21:04:23 +08:00
Redkale
e6b71a3975 2018-05-03 20:10:19 +08:00
Redkale
ff5049edc9 2018-05-03 15:33:38 +08:00
Redkale
a34218367b 2018-05-03 09:52:50 +08:00
Redkale
f712107fb8 2018-05-02 20:46:38 +08:00
Redkale
fb3dd6049d 2018-05-02 20:28:03 +08:00
Redkale
13bd467152 2018-05-02 14:59:57 +08:00
Redkale
d934f615ca 2018-05-02 09:22:10 +08:00
Redkale
5e5280a7fd 2018-05-02 08:28:18 +08:00
Redkale
be2a4d252f 2018-05-02 08:13:14 +08:00
Redkale
0392fd68a8 2018-05-01 12:14:52 +08:00
Redkale
e642854e99 2018-05-01 11:54:04 +08:00
Redkale
1a42292725 2018-05-01 10:58:59 +08:00
Redkale
c523a761c5 2018-04-30 14:27:15 +08:00
Redkale
a416ae564a 2018-04-30 14:14:54 +08:00
Redkale
ecd647ecc4 修复Keep-Alive的HTTP请求返回响应包中没有包含Keep-Alive的信息的 2018-04-30 09:37:17 +08:00
Redkale
50d0096492 2018-04-28 22:05:35 +08:00
Redkale
1a2d43479f 2018-04-28 21:57:34 +08:00
Redkale
2416e93004 2018-04-28 21:44:03 +08:00
Redkale
db99445878 2018-04-28 21:36:46 +08:00
Redkale
18459b71c2 2018-04-28 20:43:11 +08:00
Redkale
16cbabc79d 2018-04-28 20:06:12 +08:00
Redkale
c470d31605 2018-04-28 20:03:01 +08:00
Redkale
cdacc30633 2018-04-28 19:56:29 +08:00
Redkale
e55d4d8a78 不含#且方法不超过6个的RestService转换RestServlet采用枚举方式列出@WebServlet.value 2018-04-28 19:32:02 +08:00
Redkale
fcd3258a73 Source增加部分CompletableFuture异常写入日志的功能 2018-04-28 09:04:08 +08:00
Redkale
a8e9822381 2018-04-27 19:00:44 +08:00
Redkale
dfdb37973f 自动注册WebSocketNode 2018-04-27 17:45:56 +08:00
Redkale
3f340a3f7e 2018-04-25 11:38:05 +08:00
Redkale
e64d522707 2018-04-20 20:54:36 +08:00
Redkale
6c05a4a038 2018-04-20 08:58:27 +08:00
Redkale
5c9279cca4 增加Http响应包中Date头的可配置功能 2018-04-19 14:43:47 +08:00
Redkale
a4ae6dd9c4 2018-04-19 14:21:36 +08:00
Redkale
ace4042649 2018-04-18 18:30:03 +08:00
Redkale
76debd5c82 2018-04-18 17:19:48 +08:00
Redkale
8c0db6db53 2018-04-17 18:30:41 +08:00
Redkale
bc99f3f295 2018-04-17 14:24:41 +08:00
Redkale
826aaf0128 2018-04-17 13:46:30 +08:00
Redkale
754861e036 2018-04-17 11:27:34 +08:00
Redkale
b1bbc50472 2018-04-17 09:19:07 +08:00
Redkale
dcb6c6d3f8 2018-04-17 08:57:56 +08:00
Redkale
3f608b91e9 2018-04-17 08:45:31 +08:00
Redkale
9d488974a4 2018-04-16 21:53:57 +08:00
Redkale
1fa834f559 2018-04-16 21:51:21 +08:00
Redkale
812f83446e 2018-04-16 13:29:12 +08:00
Redkale
3497ab0c73 2018-04-16 08:31:24 +08:00
Redkale
78de131f83 2018-04-16 08:21:08 +08:00
Redkale
3a8ffa11fe 2018-04-15 21:07:03 +08:00
Redkale
dd62d82005 2018-04-14 13:38:13 +08:00
Redkale
7b9c71dcda 2018-04-14 13:13:13 +08:00
Redkale
4a518f1309 2018-04-14 12:52:20 +08:00
Redkale
3a0a717765 2018-04-14 12:50:13 +08:00
Redkale
60bdf4d137 2018-04-14 11:22:32 +08:00
Redkale
0ec329927a 2018-04-14 09:55:17 +08:00
Redkale
6a616b4652 2018-04-13 16:19:05 +08:00
Redkale
0bf7ccd701 2018-04-13 16:04:12 +08:00
Redkale
c924d936f3 2018-04-13 08:31:19 +08:00
Redkale
ef1c437191 HttpResponse的ContentType默认值可配置 2018-04-12 13:30:28 +08:00
Redkale
6e6d0529d6 2018-04-11 17:21:05 +08:00
Redkale
2ab179568f 2018-04-11 09:23:41 +08:00
Redkale
dab56caa98 2018-04-10 14:15:50 +08:00
Redkale
67afd13fbb 2018-04-10 11:35:11 +08:00
Redkale
3a26ddd539 2018-04-09 17:52:57 +08:00
Redkale
5197d63c70 RetLabel支持多语言版, RetLoader的load方法过期, 替换为loadMap 2018-04-09 17:28:26 +08:00
Redkale
3d136b843e 2018-04-09 14:38:40 +08:00
Redkale
388b7fbba7 2018-04-09 14:01:48 +08:00
Redkale
a833f20729 2018-04-09 10:12:44 +08:00
Redkale
d3c63bf35a 2018-04-04 14:03:55 +08:00
Redkale
5a0eff2b67 更新asm版本 2018-04-04 13:46:27 +08:00
Redkale
e64a75cfab 2018-04-03 16:16:10 +08:00
Redkale
2d31b8521d 2018-04-03 16:14:42 +08:00
Redkale
60225e3f5f 修复带空格的路径无法启动bat脚本的BUG 2018-04-03 15:19:02 +08:00
Redkale
aeb7b38474 Redkale 1.9.3 开始 2018-04-03 15:16:32 +08:00
Redkale
bfbcab4009 2018-04-03 08:29:42 +08:00
Redkale
742c352080 2018-04-02 20:53:23 +08:00
Redkale
643827354c 2018-04-02 19:29:55 +08:00
Redkale
2f7bebfc17 2018-04-02 18:48:56 +08:00
Redkale
7bf8d60ddf 2018-04-02 16:28:21 +08:00
Redkale
09c51b6b4e 2018-04-02 16:26:35 +08:00
Redkale
84f6ce58a0 2018-04-02 14:48:23 +08:00
Redkale
9e90ae5285 2018-04-02 14:08:20 +08:00
Redkale
93b1c9f0d9 2018-04-02 13:22:45 +08:00
Redkale
dab8ed8ceb 2018-03-31 11:27:11 +08:00
Redkale
f016e49111 2018-03-31 11:15:58 +08:00
Redkale
b403f22284 2018-03-31 10:46:21 +08:00
Redkale
ccb9ac93f7 ConvertFactory增加registerIgnoreAll配置 2018-03-31 10:33:57 +08:00
Redkale
72935f1ebe 2018-03-31 10:28:33 +08:00
Redkale
1f7d46219a net和WebSokcet模块增加Cryptor功能 2018-03-30 20:38:29 +08:00
Redkale
9094f76de2 Utility增加contains系列方法 2018-03-30 19:53:20 +08:00
Redkale
d67cbeb3f2 2018-03-30 17:42:18 +08:00
Redkale
90562ebd04 2018-03-30 17:25:57 +08:00
Redkale
b14e14659c 2018-03-30 08:56:00 +08:00
Redkale
84a15afc9a 2018-03-30 08:39:15 +08:00
Redkale
8c1aba5608 Transport.pollConnection的负载均衡策略改成轮询 2018-03-29 20:21:31 +08:00
Redkale
a72c689f07 2018-03-29 19:14:20 +08:00
Redkale
1d74f34575 2018-03-29 19:10:50 +08:00
Redkale
a24092d391 TransportStrategy增加offerConnection方法 2018-03-29 19:02:16 +08:00
Redkale
097ae701c1 2018-03-29 11:18:22 +08:00
Redkale
e250a593a7 完善Transport.pollConnection中连接池功能 2018-03-29 11:14:13 +08:00
Redkale
1547e6b714 Reproduce支持public field和setter、getter混合 2018-03-29 08:33:55 +08:00
Redkale
9f14224269 Reproduce增加不同字段名可以赋值的功能 2018-03-28 14:55:40 +08:00
Redkale
ecc54f9bd5 2018-03-28 09:32:21 +08:00
Redkale
521ee56d31 2018-03-28 08:59:47 +08:00
Redkale
f9da063532 2018-03-24 11:37:28 +08:00
Redkale
5070c27f6a 2018-03-24 11:34:24 +08:00
Redkale
c0664bb0a9 2018-03-24 11:28:25 +08:00
Redkale
f8c92f1ec4 2018-03-24 11:18:48 +08:00
Redkale
01930cfdc8 屏蔽sun.misc.Unsafe 2018-03-24 11:15:38 +08:00
Redkale
e76e321765 删掉过期的AsyncHandler 2018-03-21 14:14:30 +08:00
Redkale
99d2db31f7 2018-03-20 19:58:24 +08:00
Redkale
fa9015447b Redkale 1.9.2 开始 2018-03-20 19:57:19 +08:00
Redkale
735ad0908b 2018-03-17 10:44:03 +08:00
Redkale
a080a6a8cc 2018-03-16 08:45:42 +08:00
Redkale
2cbc51cfdf 2018-03-14 21:21:23 +08:00
Redkale
8631b4bdf5 Entity数据库实体类支持AtomicInteger、AtomicLong字段类型 2018-03-14 17:36:29 +08:00
Redkale
285cb86891 RetResult增加successFuture方法 2018-03-14 14:56:42 +08:00
Redkale
bf535a7161 2018-03-13 09:28:13 +08:00
Redkale
34e37471b8 2018-03-12 21:50:17 +08:00
Redkale
e223548b23 2018-03-12 21:41:36 +08:00
Redkale
3a13d242f6 2018-03-12 20:54:24 +08:00
Redkale
204e6ec99f 2018-03-12 10:04:53 +08:00
Redkale
7e348782e4 2018-03-09 19:05:37 +08:00
Redkale
a4cbe7db17 2018-03-09 09:33:42 +08:00
Redkale
f8101acb4b 2018-03-07 19:55:02 +08:00
Redkale
9ed2d59317 2018-03-07 12:50:26 +08:00
Redkale
0329ad7832 2018-03-07 12:13:06 +08:00
Redkale
53df45456f 删掉对sun.misc.Unsafe的依赖和替换过期方法Class.newInstance() 2018-03-07 11:31:11 +08:00
Redkale
93698bacff Redkale 1.9.1 开始 2018-03-07 08:30:15 +08:00
Redkale
9fbf63f720 2018-02-28 08:58:34 +08:00
Redkale
b49c334f9f AsyncConnection增加SSLContext属性,便于以后增加SSL功能 2018-02-28 08:56:47 +08:00
Redkale
a374e1278b 2018-02-11 15:57:13 +08:00
Redkale
0a16fb85bd 2018-02-11 15:07:38 +08:00
Redkale
419d5bae09 2018-02-11 14:14:52 +08:00
Redkale
d78f3565de 2018-02-11 13:36:59 +08:00
Redkale
4814e7db74 2018-02-11 12:58:03 +08:00
Redkale
3470fd35d5 2018-02-11 12:53:47 +08:00
Redkale
2915bae474 2018-02-11 12:47:10 +08:00
Redkale
ae9be7ac25 2018-02-11 11:23:36 +08:00
Redkale
4b9cb3716b 更改临时文件生成的目录结构 2018-02-09 09:20:01 +08:00
Redkale
38bd9fb204 2018-02-08 16:37:18 +08:00
Redkale
433c0db4fb 2018-02-08 16:34:10 +08:00
Redkale
ccebc18b85 2018-02-08 16:12:14 +08:00
Redkale
6fb85eb9ca 2018-02-08 15:56:08 +08:00
Redkale
c2dad0807f 2018-02-08 15:30:35 +08:00
Redkale
d6ba4a1ab7 2018-02-08 14:41:02 +08:00
Redkale
f9fae91c71 2018-02-08 14:13:38 +08:00
Redkale
fdb7ca29bc SNCP、REST支持部分含泛型继承的类 2018-02-08 10:44:38 +08:00
Redkale
722ab55591 2018-02-07 19:32:45 +08:00
Redkale
450b390ac4 Convert支持部分TypeVariable 2018-02-07 14:50:43 +08:00
Redkale
39eca5d39e 2018-02-06 16:14:39 +08:00
Redkale
4a4b9ad1d2 2018-02-02 10:46:17 +08:00
Redkale
ea01647200 2018-02-02 10:42:31 +08:00
Redkale
1f8faa8afd AsmMethodVisitor类迁移 2018-02-02 09:19:42 +08:00
Redkale
2b78d145ea 2018-02-01 18:39:14 +08:00
Redkale
e69b8bcd64 2018-02-01 09:42:27 +08:00
Redkale
3dcd85e902 Context增加SSLContext属性 2018-01-31 10:45:45 +08:00
Redkale
deab165c7f 增加java.util.logging.FileHandler.denyreg属性配置 2018-01-31 10:43:22 +08:00
Redkale
e405c4dc15 2018-01-30 13:39:27 +08:00
Redkale
c5260584fa 2018-01-30 13:28:57 +08:00
Redkale
15cd16e771 2018-01-30 11:27:14 +08:00
Redkale
11d8d36c12 2018-01-30 09:58:05 +08:00
Redkale
d542ac9110 2018-01-30 09:12:08 +08:00
Redkale
3d0e4ee7d7 2018-01-30 09:01:19 +08:00
Redkale
379a399d29 2018-01-29 21:39:53 +08:00
Redkale
26f0324573 2018-01-29 21:31:59 +08:00
Redkale
a71f1a17dd 2018-01-29 21:26:35 +08:00
Redkale
9f4f459ea8 2018-01-29 16:16:50 +08:00
Redkale
adafb9645c 2018-01-29 14:27:14 +08:00
Redkale
09c825bbcd 2018-01-29 14:11:25 +08:00
Redkale
255c1d945c 增加模板引擎规范API 2018-01-29 13:56:06 +08:00
Redkale
c5eb49d12c 2018-01-27 09:27:07 +08:00
Redkale
ad690724a6 2018-01-27 09:17:16 +08:00
Redkale
1573e79041 WebSocketParam增加getNames方法 2018-01-26 20:29:22 +08:00
Redkale
4d8026ec99 2018-01-26 11:33:53 +08:00
Redkale
5c1c2b18e4 WebSocket实现preOnMessage功能 2018-01-26 11:10:45 +08:00
Redkale
66baca51d7 CacheSource增加getIfAbsent系列方法 2018-01-25 14:24:28 +08:00
Redkale
355441e795 Creator的getConstructorField方法增加对子类字段的支持 2018-01-24 10:50:08 +08:00
Redkale
902fd70eb4 ConvertDisabled增加ConvertType属性 2018-01-16 15:58:24 +08:00
Redkale
4ce7eee4aa 2018-01-16 15:47:57 +08:00
Redkale
6a73c2a697 2018-01-16 15:44:40 +08:00
Redkale
f713669d1f 2018-01-16 14:24:00 +08:00
Redkale
d5365af373 2018-01-16 11:49:58 +08:00
Redkale
ccffa0d5c2 修复单个WebSocket并发问题 2018-01-15 15:11:25 +08:00
Redkale
0ee5b911d2 修复单个WebSocket并发问题 2018-01-15 14:50:03 +08:00
Redkale
c92d17abbc 2018-01-14 16:39:21 +08:00
Redkale
ef5ef4ed72 2018-01-13 10:07:23 +08:00
Redkale
ba5f4a24c7 bufferCapacity的默认值统一调整成32K 2018-01-13 10:05:13 +08:00
Redkale
1cd5fe0b02 增加SERVER_EXECUTOR线程池的资源注入 2018-01-12 09:14:10 +08:00
Redkale
21af487aab 限制标记@RestOnMessage方法的条件 2018-01-11 19:13:14 +08:00
Redkale
f254519a1c 2018-01-11 14:28:40 +08:00
Redkale
26fc039aa5 去掉java.beans.ConstructorProperties,使用org.redkale.util.ConstructorParameters 代替 2018-01-11 11:05:39 +08:00
Redkale
7d3e4529af 2018-01-10 10:22:46 +08:00
Redkale
bcefaee3e9 2018-01-09 16:48:39 +08:00
Redkale
3933eaa1cf 2018-01-08 19:36:26 +08:00
Redkale
28251435e4 增加ConvertDisabled功能 2018-01-08 11:23:05 +08:00
Redkale
d29dc320c3 RetResult增加clearAttach方法 2018-01-06 14:04:33 +08:00
Redkale
d14a939acb 2018-01-05 18:41:03 +08:00
Redkale
e20619e0c9 自动删除0字节的日志文件 2018-01-05 08:42:15 +08:00
Redkale
8ff829f1b1 2018-01-05 08:24:11 +08:00
Redkale
402255ba0d Flipper的limit可以设置为0 2018-01-04 20:02:51 +08:00
Redkale
7250bf8047 Update README.md 2018-01-04 08:27:11 +08:00
Redkale
c76436cd3c Update README.md 2018-01-03 19:35:49 +08:00
Redkale
9b85562595 Update README.md 2018-01-03 19:35:13 +08:00
Redkale
4798ddfe19 2018-01-03 19:17:27 +08:00
Redkale
dd197cfa24 将JDK内置的jdk.internal.org.objectweb.asm包拷贝一份进redkale 2018-01-03 19:04:58 +08:00
Redkale
844b9c19e5 2018-01-03 19:01:34 +08:00
Redkale
5f6f1ebc44 2018-01-03 16:31:51 +08:00
Redkale
71b91e6896 2018-01-03 16:27:35 +08:00
Redkale
30d4296687 2018-01-03 16:26:10 +08:00
Redkale
7b0a576b00 2018-01-03 16:11:11 +08:00
Redkale
808a3c2e9c WebSocket模块broadcastMessage方法增加WebSocketRange过滤参数 2018-01-03 11:17:00 +08:00
Redkale
c700ffbadc 2018-01-02 16:58:49 +08:00
Redkale
e2057676bd 优化WebSocketNode.sendMessage 2018-01-02 16:42:51 +08:00
Redkale
f7dfb32849 Redkale 1.9.0 开始 2018-01-02 15:47:15 +08:00
Redkale
6413161dc8 net包优化 2017-12-29 10:19:20 +08:00
Redkale
46a89d9847 @RestHeader增加支持Host、Content-Type、Connection选项 2017-12-29 08:31:19 +08:00
Redkale
d83d6b5671 2017-12-29 08:29:27 +08:00
Redkale
b1abe91bd2 2017-12-28 21:05:20 +08:00
Redkale
bf4138178b 2017-12-28 21:04:55 +08:00
Redkale
5b99084616 2017-12-28 19:59:45 +08:00
Redkale
b95064b87e 2017-12-28 19:10:11 +08:00
Redkale
e1eece34b7 增加restart脚本 2017-12-28 11:28:47 +08:00
Redkale
19d6a06bfa 还原 2017-12-28 10:53:34 +08:00
Redkale
2fd13d1481 2017-12-28 10:40:25 +08:00
Redkale
23a0a80e3a Transport增加readTimeoutSecond、writeTimeoutSecond配置项 2017-12-28 10:24:15 +08:00
Redkale
bb493d43b5 RetResult的attach属性由Map<String, String> 改成 Map<String, Serializable> 2017-12-28 10:19:49 +08:00
Redkale
ef9eaa0a66 DataSource.updateColumn系列方法屏蔽掉limit功能 2017-12-28 10:16:21 +08:00
Redkale
1d640f943a CacheSource增加existsSetItem系列方法 2017-12-28 10:14:10 +08:00
Redkale
84f5f065ad Redkale 1.8.9 开始 2017-12-28 10:13:04 +08:00
Redkale
921aedaf9d 增加Optional的序列化和反序列化 2017-12-25 10:12:01 +08:00
Redkale
0f545923b2 2017-12-23 10:39:46 +08:00
Redkale
5b32a91874 2017-12-23 10:14:27 +08:00
Redkale
25b2528416 2017-12-23 10:11:38 +08:00
Redkale
d29c95c38f 2017-12-22 10:48:31 +08:00
Redkale
a661ab2ff5 Utility增加max、min方法 2017-12-21 19:14:01 +08:00
Redkale
ac08ebee75 Utility增加joining方法 2017-12-21 17:39:45 +08:00
Redkale
8e1a287ed1 2017-12-21 17:33:18 +08:00
Redkale
9b656b3970 2017-12-21 16:50:21 +08:00
Redkale
a1c0bbf413 2017-12-21 16:24:08 +08:00
Redkale
2ad8c5d425 2017-12-21 16:19:41 +08:00
Redkale
75aaa980cf 2017-12-21 16:09:17 +08:00
Redkale
7c55326d23 2017-12-20 18:49:47 +08:00
Redkale
aa3ade5912 Convert增加AtomicIntegerSimpledCoder 2017-12-20 18:45:14 +08:00
Redkale
c692deebe9 优化MapEncoder 2017-12-20 14:20:02 +08:00
Redkale
9ff161c97d 增加WebSocket在onOpen和createUserid方法里返回无效用户信息前也可以发送信息 2017-12-20 08:54:54 +08:00
Redkale
5b1f820621 2017-12-19 20:07:57 +08:00
Redkale
30b2cffcb8 2017-12-19 16:40:58 +08:00
Redkale
709439bfca 2017-12-18 11:48:36 +08:00
Redkale
34adb238f7 ObjectPool实现Consumer接口,且将offer设为过期,建议使用accept方法 2017-12-18 10:00:18 +08:00
Redkale
76c54f8d54 修复部分带有@RestConvert方法生成RestServlet时出现的BUG 2017-12-16 16:32:21 +08:00
Redkale
6196c05f12 2017-12-16 10:42:50 +08:00
Redkale
37df0af56c Redkale 1.8.8 开始 2017-12-16 09:40:30 +08:00
Redkale
8a5e1252ab 2017-12-15 09:06:26 +08:00
Redkale
ae5430af42 2017-12-14 19:25:10 +08:00
Redkale
13cf188e25 WebSocketEngine增加forEachLocalWebSocket方法 2017-12-14 19:10:49 +08:00
Redkale
41d3dea1ac 2017-12-14 18:43:23 +08:00
Redkale
be816088f5 增加对IntStream、LongStream、DoubleStream的序列化支持 2017-12-14 18:37:54 +08:00
Redkale
5bef900b76 2017-12-14 16:01:13 +08:00
Redkale
52f61b0f96 2017-12-14 15:56:31 +08:00
Redkale
b5a4646e3b 2017-12-14 15:50:48 +08:00
Redkale
d055d5c824 2017-12-14 15:09:20 +08:00
Redkale
f14ef05c88 HttpResponse增加finish(Object)系列方法 2017-12-14 15:02:16 +08:00
Redkale
426506324f 2017-12-14 10:58:27 +08:00
Redkale
7a5e58a112 删掉AsyncHandler, 采用CompletionHandler代替 2017-12-14 10:42:24 +08:00
Redkale
2e0c58cbea WebSocket增加changeUserid功能 2017-12-12 09:33:56 +08:00
Redkale
9ded3fbb9a Update README.md 2017-12-11 18:51:48 +08:00
Redkale
acbc1032e6 Update README.md 2017-12-11 18:50:59 +08:00
Redkale
d8186b00ba 启动打印java.version信息 2017-12-11 11:39:57 +08:00
Redkale
767adcbefe 2017-12-08 19:44:39 +08:00
Redkale
67df072275 HttpRequest增加getParametersToString方法 2017-12-08 19:38:54 +08:00
Redkale
dab70af4d4 2017-12-08 14:27:22 +08:00
Redkale
b42826692d 2017-12-08 11:50:12 +08:00
Redkale
e2ab4b20c9 HttpResult支持byte[]、ByteBuffer和ByteBuffer[] 2017-12-08 11:36:24 +08:00
Redkale
511ee8a6df EntityInfo增加getQueryColumns方法 2017-12-06 18:58:30 +08:00
Redkale
463269a796 增加ApplicationListener功能 2017-12-06 14:33:39 +08:00
Redkale
2d4b865432 RestWebSocket增加anyuser功能 2017-12-06 10:20:13 +08:00
Redkale
1da73429f7 对SNCP的Address进行IPv4判断 2017-12-04 09:48:52 +08:00
Redkale
e97e6b8262 2017-11-29 14:06:01 +08:00
Redkale
e6bc34d6f8 2017-11-29 14:03:53 +08:00
Redkale
f1c4ac9e67 2017-11-29 14:01:57 +08:00
Redkale
de6c6076e4 【新增功能】DataSource可以通过application.xml配置 2017-11-29 13:56:26 +08:00
Redkale
a36e3d3819 2017-11-29 12:05:18 +08:00
Redkale
043b847f05 DataSource增加getType()方法 2017-11-29 12:01:42 +08:00
Redkale
65bc8192f0 DataJdbcSource增加preConstruct方法,方便重载 2017-11-29 11:28:10 +08:00
Redkale
71e0b60200 增加manifest的MimeType 2017-11-28 20:03:29 +08:00
Redkale
99dc7ac189 2017-11-25 16:48:59 +08:00
Redkale
8605c44f14 Redkale 1.8.7 开始 2017-11-25 14:40:39 +08:00
Redkale
c47e301263 2017-11-24 19:51:46 +08:00
Redkale
6c11ef70d4 2017-11-23 08:56:40 +08:00
Redkale
dddb2397c4 2017-11-22 21:07:29 +08:00
Redkale
f66803b9fd 2017-11-22 21:06:48 +08:00
Redkale
0801ce8cad 2017-11-22 20:08:23 +08:00
Redkale
5a690912c1 2017-11-22 16:07:39 +08:00
Redkale
a3dddd20c7 修复FilterBean对List<>不支持的BUG 2017-11-17 15:56:18 +08:00
Redkale
7200a74b18 2017-11-17 15:44:47 +08:00
Redkale
3847cf47e4 2017-11-17 14:19:22 +08:00
Redkale
0b5a79c1d8 2017-11-17 10:38:43 +08:00
Redkale
685667fd69 修改WebSocketPacket解析协议方式,并修复多报并发请求导致后面的消息丢失的BUG 2017-11-16 17:11:11 +08:00
Redkale
72e81bd034 2017-11-16 17:09:48 +08:00
Redkale
39eadcd08b 2017-11-16 09:24:14 +08:00
Redkale
a46f79a448 2017-11-15 21:23:21 +08:00
Redkale
5ddca03fb6 2017-11-15 21:07:54 +08:00
Redkale
0bd5787992 2017-11-15 21:06:17 +08:00
Redkale
bf88c4da06 2017-11-15 19:51:49 +08:00
Redkale
5e72e782cc 2017-11-15 17:14:18 +08:00
Redkale
3c0609fa0e 修改DataJdbcSource的directQuery实现 2017-11-15 17:12:49 +08:00
Redkale
945f9f9ef5 2017-11-15 11:00:08 +08:00
Redkale
7c5ac7970e 2017-11-15 08:49:17 +08:00
Redkale
68f0c1de29 2017-11-15 08:46:12 +08:00
Redkale
337a2a3038 CacheSource增加getString/getLong一系列方法 2017-11-14 20:35:31 +08:00
Redkale
2a5e0e82be WebSocketNode的CacheSource资源名改成与WebSocketNode同名 2017-11-14 11:42:39 +08:00
Redkale
e0b2120ee5 2017-11-14 10:54:56 +08:00
Redkale
ac5662114a 2017-11-14 10:44:13 +08:00
Redkale
f2963e01e0 Transport的pollConnection方法改成异步模式 2017-11-13 21:27:28 +08:00
Redkale
fc54fc3f24 2017-11-13 21:09:24 +08:00
Redkale
41990e7e6a AsyncConnection提供createTCP方法。异步构建AsyncConnection 2017-11-13 19:43:01 +08:00
Redkale
01e8649e2a Context提供createAsynchronousChannelGroup方法 2017-11-13 19:15:45 +08:00
Redkale
71ead72dec 修复WebSocketNode在远程模式下使用SNCP序列化导致目标服务器没有对应的JavaBean类而无法解析的BUG 2017-11-13 17:22:01 +08:00
Redkale
da600ecf20 修复WebSocketNode在半远程模式下SNCP出异常的BUG 2017-11-13 16:22:48 +08:00
Redkale
d46807a585 2017-11-13 14:54:23 +08:00
Redkale
571d13075b 2017-11-13 14:43:45 +08:00
Redkale
3ad8eeaae6 2017-11-13 14:25:30 +08:00
Redkale
e540128154 修复WebSocketNode无法获取SNCP_ADDR的BUG 2017-11-13 13:19:43 +08:00
Redkale
c6d83440bb WebSocketServlet的maxconns改成wsmaxconns 2017-11-13 10:16:50 +08:00
Redkale
97f43a4d8d 2017-11-13 09:39:51 +08:00
Redkale
6fddd8b53b 修复将null开头的字符串(例如nullaxx)都视为null的BUG 2017-11-11 23:57:45 +08:00
Redkale
98a6c3ef79 AnyValue增加forEach方法 2017-11-11 13:39:08 +08:00
Redkale
6e70f2043e 增加TCP级别上的最大连接数限制 2017-11-11 10:37:25 +08:00
Redkale
123b94398a 修复Json中不带引号的n开头且长度大于3的字符串转成String时不能正常解析的BUG 2017-11-10 19:56:21 +08:00
Redkale
40c19c1521 CacheSource增加incr或decr方法 2017-11-10 19:33:10 +08:00
Redkale
7089fae390 2017-11-10 19:09:28 +08:00
Redkale
936fe8d1ab SNCP连接增加心跳功能 2017-11-10 18:04:43 +08:00
Redkale
7780e0090c 修复iconst问题 2017-11-10 17:48:33 +08:00
Redkale
1a7dc97335 修改logger的finest方式 2017-11-10 11:31:41 +08:00
Redkale
9af8c863b1 修复ASM的BIPUSH问题,RestWebSocket增加maxconns文件配置功能 2017-11-10 11:01:58 +08:00
Redkale
2c13224fcc CacheSource增加getType方法 2017-11-09 15:53:36 +08:00
Redkale
5e13575e84 2017-11-09 10:21:16 +08:00
Redkale
eabdc13c53 2017-11-09 10:17:31 +08:00
Redkale
7261bcfadb CacheSource改善 2017-11-08 16:20:04 +08:00
Redkale
0569e87d4e 2017-11-08 15:02:56 +08:00
Redkale
5c339f6f66 2017-11-08 14:46:28 +08:00
Redkale
44eada2697 2017-11-08 11:14:39 +08:00
Redkale
3e0b9daeaf CacheSource中的key固定使用String类型 2017-11-08 11:06:55 +08:00
Redkale
3061422d83 2017-11-08 09:40:55 +08:00
Redkale
4280464f85 2017-11-08 09:39:38 +08:00
Redkale
2b1d09b027 WebSocket增加最大连接数设置功能 2017-11-07 17:39:30 +08:00
Redkale
4f3c2e071a RestConvert 增加 skipIgnore 功能 2017-11-04 10:47:40 +08:00
Redkale
d2aacf7b8c @Resource支持含{system.property.xxx}模式 2017-11-03 16:40:13 +08:00
Redkale
fbb1fb5a5f 2017-11-03 11:58:42 +08:00
Redkale
c9187a78bc 2017-11-03 11:19:42 +08:00
Redkale
d984ab2a8f 2017-11-03 11:03:01 +08:00
Redkale
ad2a3f0d54 改造Transport的构造函数,便于TransportFactory统一管理 2017-11-02 19:04:55 +08:00
Redkale
e559379294 Resource依赖注入支持system.property.开头的系统变量 2017-11-02 17:42:16 +08:00
Redkale
e125aa9885 2017-11-02 15:34:52 +08:00
Redkale
8026ebb215 2017-11-02 11:00:16 +08:00
Redkale
45b04da483 RestWebSocket的resourceName增加可配功能,通过System.getProperty可以配置 2017-11-02 10:09:29 +08:00
Redkale
0da5867b70 2017-10-31 14:29:22 +08:00
Redkale
b1f51b1c30 WebSocket补上识别Close事件,之前漏掉了 2017-10-31 11:28:53 +08:00
Redkale
054253fb90 AsyncConnection增加获取最后一次进行读写IO操作时间的方法 2017-10-30 19:19:31 +08:00
Redkale
141041dbba Redkale 1.8.6 开始 2017-10-30 17:01:10 +08:00
Redkale
500545fc93 DataSource.queryMap重载了FilterBean、FilterNode参数等系列方法 2017-10-30 09:49:34 +08:00
Redkale
78f1bd90f4 2017-10-27 16:42:01 +08:00
Redkale
f5a04319d5 2017-10-26 20:04:32 +08:00
Redkale
76ce6787d1 2017-10-26 14:48:15 +08:00
Redkale
bd53d4a8ab 2017-10-26 14:17:24 +08:00
Redkale
53b11116b9 DataSource增加queryMap系列方法 2017-10-26 13:20:05 +08:00
Redkale
734b1bbbb4 2017-10-26 10:23:43 +08:00
Redkale
f014bffb6c Redkale 1.8.5 开始 2017-10-25 09:51:08 +08:00
Redkale
f633e72c5f 2017-10-25 09:26:57 +08:00
Redkale
b8c85284ab 2017-10-25 09:21:48 +08:00
Redkale
a3af6749f6 暂时屏蔽Persist功能 2017-10-25 09:21:00 +08:00
Redkale
9128dffe35 新增Persist注解, 用于Service成员变量数据的临时缓存 2017-10-24 17:30:51 +08:00
Redkale
9273f2917e 2017-10-24 15:23:43 +08:00
Redkale
4d9d09af8c 2017-10-24 10:28:21 +08:00
Redkale
33beb60efe 2017-10-23 11:38:11 +08:00
Redkale
129bcf2f78 2017-10-22 16:01:20 +08:00
Redkale
f6c7dde28f Server增加setThreads方法,可以动态修改线程池的大小 2017-10-22 15:39:00 +08:00
Redkale
8fcd33b511 Copy一份javax.annotation.Resource源码到Redkale中,因JDK9中java.base模块中不包含javax.annotation.Resource 2017-10-22 13:01:03 +08:00
Redkale
66ec26e0ce 2017-10-22 11:14:49 +08:00
Redkale
969f7ada82 2017-10-22 11:04:00 +08:00
Redkale
7e37889372 增加Priority功能, 可以对Service、Filter、HttpServlet的加载顺序进行优先级设置,同时删掉Filter的getIndex方法 2017-10-22 11:00:09 +08:00
Redkale
c819d4d45b WATCH协议服务器默认host改为127.0.0.1 2017-10-22 10:13:24 +08:00
Redkale
6dc59b7abc 2017-10-21 11:07:16 +08:00
Redkale
60b24fa1ae 2017-10-20 10:58:31 +08:00
Redkale
b784993110 WebSocket的sendMessage系列方法增加Stream userids参数 2017-10-20 10:45:56 +08:00
Redkale
cc150a2cc6 @RestUploadFile标记的File对象可以获取到用户上传的文件名 2017-10-20 09:41:34 +08:00
Redkale
f6b407aa44 WebSocket识别Single模式,Single模式下重复登陆时默认会关闭之前的WebSocket连接 2017-10-18 10:47:43 +08:00
Redkale
a69d813bf5 WebSocket增加forceCloseWebSocket系列方法 2017-10-18 10:05:10 +08:00
Redkale
d1eff6144d convertMapTo方法识别CompletableFuture 2017-10-18 09:16:55 +08:00
Redkale
99589387d8 RetResult增加Map<String, String> attach成员变量 2017-10-17 09:42:32 +08:00
Redkale
e0041235fe WebSocket增加sendMap方法 2017-10-16 11:19:58 +08:00
Redkale
84b4eee7b5 重载WebSocket的sendMessage和broadcastMessage系列方法,增加Convert参数 2017-10-16 10:48:14 +08:00
Redkale
96c0a9bfe4 2017-10-15 22:22:31 +08:00
Redkale
89ad976744 增加BigDecimal的序列化和反序列化 2017-10-15 22:01:16 +08:00
Redkale
0eedc2c180 Redkale 1.8.4 开始 2017-10-15 21:59:59 +08:00
Redkale
8b3658143a 修复HttpResponse.finishFile传输偶尔异常的BUG 2017-09-25 11:40:49 +08:00
Redkale
6d69ff546b 2017-09-13 11:10:24 +08:00
Redkale
9555e3c9b9 2017-09-13 10:43:34 +08:00
Redkale
744634dbdd ResourceFactory 增加 public <A> List<A> query(final BiPredicate<String, A> predicate) 方法 2017-09-12 19:34:50 +08:00
Redkale
de5ee844c4 Convert 增加 convertMapTo 系列方法, HttpResponse增加 finishMapJson 系列方法 2017-09-09 22:36:35 +08:00
Redkale
ae73cee357 2017-09-09 13:24:19 +08:00
Redkale
d1cf9be8d7 AnyEncoder增加convertMapTo方法 2017-09-09 13:23:35 +08:00
Redkale
43ae77ab33 2017-09-01 11:13:22 +08:00
Redkale
182a75cfad 修复创建RestServlet时方法内含try/catch导致获取方法参数名错位的BUG 2017-09-01 10:51:41 +08:00
Redkale
222dc0edce 2017-08-28 21:54:48 +08:00
Redkale
c7a81513fe Redkale 1.8.3 开始 2017-08-28 19:20:51 +08:00
295 changed files with 37601 additions and 6667 deletions

View File

@@ -1,6 +1,6 @@
<h1>项目介绍</h1>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale (中文名: 红菜苔,湖北武汉的一种特产蔬菜) 是基于Java 8全新的微服务框架 包含HTTP、WebSocket、TCP/UDP、数据序列化、数据缓存、依赖注入等功能。 本框架致力于简化集中式和微服务架构的开发,在增强开发敏捷性的同时保持高性能。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale (中文名: 红菜苔,一种湖北特产蔬菜) 是基于Java 8全新的微服务框架 包含HTTP、WebSocket、TCP/UDP、数据序列化、数据缓存、依赖注入等功能。 本框架致力于简化集中式和微服务架构的开发,在增强开发敏捷性的同时保持高性能。
</p>
<strong>RedKale 有如下主要特点:</strong>
<ol>
@@ -19,10 +19,9 @@
</p>
&nbsp;&nbsp;&nbsp;由于RedKale使用了JDK 8 内置的ASM包所以需要在源码工程中的编译器选项中加入 <b>-XDignore.symbol.file=true</b>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<h5>详情请访问:&nbsp;&nbsp;&nbsp;&nbsp;<a href='https://redkale.org' target='_blank'>https://redkale.org</a></h5>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<h5>基本文档:&nbsp;&nbsp;&nbsp;&nbsp;<a href='https://redkale.org/articles.html' target='_blank'>https://redkale.org/articles.html</a></h5>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<h5>欢迎加入Redkale QQ群: 527523235</h5>
&nbsp;

View File

@@ -4,4 +4,4 @@ SET APP_HOME=%~dp0
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
java -DCMD=APIDOC -DAPP_HOME=%APP_HOME% -classpath %APP_HOME%\lib\* org.redkale.boot.Application
java -DCMD=APIDOC -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application

9
bin/restart.bat Normal file
View File

@@ -0,0 +1,9 @@
@ECHO OFF
SET APP_HOME=%~dp0
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
call "%APP_HOME%\bin\shutdown.bat"
call "%APP_HOME%\bin\start.bat"

20
bin/restart.sh Normal file
View File

@@ -0,0 +1,20 @@
#!/bin/sh
export LC_ALL="zh_CN.UTF-8"
APP_HOME=`dirname "$0"`
cd "$APP_HOME"/..
APP_HOME=`pwd`
if [ ! -f "$APP_HOME"/conf/application.xml ]; then
APP_HOME="$APP_HOME"/..
fi
cd "$APP_HOME"
"$APP_HOME"/bin/shutdown.sh
"$APP_HOME"/bin/start.sh

View File

@@ -4,4 +4,4 @@ SET APP_HOME=%~dp0
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
java -DCMD=SHUTDOWN -DAPP_HOME=%APP_HOME% -classpath %APP_HOME%\lib\* org.redkale.boot.Application
java -DCMD=SHUTDOWN -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application

View File

@@ -4,15 +4,20 @@ export LC_ALL="zh_CN.UTF-8"
APP_HOME=`dirname "$0"`
cd "$APP_HOME"/..
APP_HOME=`pwd`
if [ ! -f "$APP_HOME"/conf/application.xml ]; then
APP_HOME="$APP_HOME"/..
fi
lib='.'
lib="$APP_HOME"/lib
for jar in `ls $APP_HOME/lib/*.jar`
do
lib=$lib:$jar
done
export CLASSPATH=$CLASSPATH:$lib
echo "$APP_HOME"
java -DCMD=SHUTDOWN -DAPP_HOME="$APP_HOME" org.redkale.boot.Application

View File

@@ -1,8 +1,8 @@
@ECHO OFF
SET APP_HOME=%~dp0
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
java -DAPP_HOME=%APP_HOME% -classpath %APP_HOME%\lib\* org.redkale.boot.Application
java -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application

View File

@@ -8,6 +8,10 @@ export LC_ALL="zh_CN.UTF-8"
APP_HOME=`dirname "$0"`
cd "$APP_HOME"/..
APP_HOME=`pwd`
if [ ! -f "$APP_HOME"/conf/application.xml ]; then
APP_HOME="$APP_HOME"/..
fi
@@ -20,5 +24,5 @@ done
export CLASSPATH=$CLASSPATH:$lib
echo "$APP_HOME"
nohup java -DAPP_HOME="$APP_HOME" org.redkale.boot.Application > "$APP_HOME"/log.out &
nohup java -DAPP_HOME="$APP_HOME" org.redkale.boot.Application > "$APP_HOME"/logs.out &

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<application port="5050">
<application port="2121">
<!-- 详细配置说明见: http://redkale.org/redkale.html#redkale_confxml -->
@@ -8,14 +8,14 @@
</resources>
<server protocol="HTTP" host="0.0.0.0" port="6060" root="root">
<server protocol="HTTP" port="6060">
<request>
<remoteaddr value="request.headers.X-RemoteAddress"/>
</request>
<response>
<defcookie domain="" path=""/>
<defcookie domain="" path="/"/>
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
<setheader name="Access-Control-Allow-Credentials" value="true"/>
</response>

View File

@@ -1,9 +1,10 @@
handlers = java.util.logging.ConsoleHandler
# handlers = java.util.logging.FileHandler
############################################################
.level = FINER
.level = FINEST
java.level = INFO
javax.level = INFO
@@ -14,11 +15,11 @@ jdk.level = INFO
java.util.logging.FileHandler.level = FINER
#10M
java.util.logging.FileHandler.limit = 10485760
java.util.logging.FileHandler.count = 10000
java.util.logging.FileHandler.limit = 10M
java.util.logging.FileHandler.count = 20
java.util.logging.FileHandler.encoding = UTF-8
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%d.log
java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-warnerr-%d.log
java.util.logging.FileHandler.append = true
java.util.logging.ConsoleHandler.level = FINER
java.util.logging.ConsoleHandler.level = FINEST

View File

@@ -6,7 +6,6 @@
<shared-cache-mode>ALL</shared-cache-mode>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/center?autoReconnect=true&amp;characterEncoding=utf8"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="1234"/>
</properties>
@@ -17,7 +16,6 @@
<shared-cache-mode>ALL</shared-cache-mode>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="javax.persistence.jdbc.user" value="system"/>
<property name="javax.persistence.jdbc.password" value="1234"/>
</properties>
@@ -26,8 +24,7 @@
<persistence-unit name="user.write" transaction-type="RESOURCE_LOCAL">
<shared-cache-mode>ALL</shared-cache-mode>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/user?autoReconnect=true&amp;characterEncoding=utf8"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/center?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="1234"/>
</properties>

View File

@@ -1 +0,0 @@
<EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD>jarĬ<EFBFBD>Ϸ<EFBFBD><EFBFBD>ڴ˴<EFBFBD>

View File

@@ -16,10 +16,6 @@
<directory>${project.basedir}/conf</directory>
<outputDirectory>conf</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.basedir}/libs</directory>
<outputDirectory>libs</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.basedir}/logs</directory>
<outputDirectory>logs</outputDirectory>

View File

@@ -63,10 +63,10 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<compilerArgument>-parameters</compilerArgument>
<encoding>UTF-8</encoding>
<compilerArguments>
<verbose />
<bootclasspath>${java.home}/lib/rt.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
@@ -113,7 +113,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<version>3.0.0</version>
<executions>
<execution>
<goals>

1
my/readme.txt Normal file
View File

@@ -0,0 +1 @@
<EFBFBD><EFBFBD>Ŀ¼<EFBFBD>µ<EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>sonatypeʱʹ<EFBFBD>ã<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڹ<EFBFBD><DAB9>̴<EFBFBD><CCB4><EFBFBD><EFBFBD><EFBFBD>

View File

@@ -34,12 +34,14 @@
<!--
【节点全局唯一】
transport节点只能有一个用于配置所有Transport的池参数没配置该节点将自动创建一个。
threads 线程总数, 默认: <group>节点数*CPU核数*8
bufferCapacity: ByteBuffer的初始化大小 默认: 8K;
bufferPoolSize ByteBuffer池的大小默认: <group>节点数*CPU核数*8
threads 线程总数, 默认: <group>节点数*CPU核数*2
bufferCapacity: ByteBuffer的初始化大小 默认: 32K;
bufferPoolSize ByteBuffer池的大小默认: 线程总数*4
readTimeoutSeconds: TCP读取超时秒数, 默认为6秒 为0表示无超时限制
writeTimeoutSeconds: TCP写入超时秒数, 默认为6秒 为0表示无超时限制
strategy: 远程请求的负载均衡策略, 必须是org.redkale.net.TransportStrategy的实现类
-->
<transport bufferCapacity="8K" bufferPoolSize="32" threads="32"/>
<transport bufferCapacity="32K" bufferPoolSize="32" threads="32" readTimeoutSeconds="6" writeTimeoutSeconds="6"/>
<!--
一个组包含多个node 同一Service服务可以由多个进程提供这些进程称为一个GROUP且同一GROUP内的进程必须在同一机房或局域网内
@@ -55,8 +57,6 @@
同一个<node>节点值只能存在一个<group>节点内即同一个addr+port只能属于一个group。
addr: required IP地址
port: required 端口
clients: 连接池数, 默认: CPU核数*4
buffers: ByteBuffer对象池的大小 默认: CPU核数*8
-->
<node addr="127.0.0.1" port="7070"/>
</group>
@@ -64,14 +64,20 @@
<!--
全局的数据源设置, 可以是CacheSource、DataSource JDBC的DataSource通常通过persistence.xml配置此处多用于CacheSource的配置
name: 资源名,用于依赖注入。
value类名必须是CacheSource或DataSource的子类且必须实现Service接口。
value类名必须是CacheSource或DataSource的子类且必须实现Service接口。如果是DataSource.class系统自动映射成DataJdbcSource.class
groups: 指定groups。
xxx: 其他属性与子节点通过Service.init方法传入的AnyValue获取。
-->
<source name="redis" value="org.redkalex.cache.RedisCacheSource" xxx="16">
<node addr="127.0.0.1" port="7070"/>
</source>
<!--
Application启动的监听事件,可配置多个节点
value: 类名必须是ApplicationListener的子类
-->
<listener value="org.redkalex.xxx.XXXApplicationListener"/>
<!--
【节点全局唯一】
全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入<property>的信息, 被注解的字段类型只能是String、primitive class
@@ -79,6 +85,9 @@
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。
load: 加载文件,多个用;隔开。
默认置入的system.property.的有:
System.setProperty("net.transport.poolmaxconns", "100");
System.setProperty("net.transport.pinginterval", "30");
System.setProperty("net.transport.checkinterval", "30");
System.setProperty("convert.json.tiny", "true");
System.setProperty("convert.bson.tiny", "true");
System.setProperty("convert.json.pool.size", "128");
@@ -86,7 +95,8 @@
System.setProperty("convert.json.writer.buffer.defsize", "4096");
System.setProperty("convert.bson.writer.buffer.defsize", "4096");
<properties>节点下也可包含非<property>节点,其节点可以通过@Resource(name="properties.xxxxxx")进行注入, 被注解的字段类型只能是AnyValue、AnyValue[]
<properties>节点下也可包含非<property>节点.
非<property>其节点可以通过@Resource(name="properties.xxxxxx")进行注入, 被注解的字段类型只能是AnyValue、AnyValue[]
-->
<properties load="config.properties">
<property name="system.property.yyyy" value="YYYYYY"/>
@@ -106,17 +116,31 @@
excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
charset: 文本编码, 默认: UTF-8
backlog: 默认10K
threads 线程数, 默认: CPU核数*16
threads 线程数, 默认: CPU核数*32
maxconns最大连接数, 小于1表示无限制 默认: 0
maxbody: request.body最大值 默认: 64K
bufferCapacity: ByteBuffer的初始化大小 默认: 8K; 如果是HTTP协议则默认: 16K + 16B (兼容HTTP 2.0、WebSocket)
bufferPoolSize ByteBuffer池的大小默认: CPU核数*512
responsePoolSize Response池的大小默认: CPU核数*256
readTimeoutSecond: 读操作超时秒数, 默认0 表示永久不超时
writeTimeoutSecond: 操作超时秒数, 默认0 表示永久不超时
bufferCapacity: ByteBuffer的初始化大小 TCP默认: 32K; (HTTP 2.0、WebSocket必须要16k以上); UDP默认: 1350B
bufferPoolSize ByteBuffer池的大小默认: 线程数*4
responsePoolSize Response池的大小默认: 线程数*2
aliveTimeoutSeconds: KeepAlive读操作超时秒数, 默认30 0表示永久不超时; -1表示禁止KeepAlive
readTimeoutSeconds: 操作超时秒数, 默认0 表示永久不超时
writeTimeoutSeconds: 写操作超时秒数, 默认0 表示永久不超时
netimpl: ProtocolServer的实现类。TCP情况下值可以是aio或nio默认值为aioUDP情况下值可以是bio默认值为bio
interceptor: 启动/关闭NodeServer时被调用的拦截器实现类必须是org.redkale.boot.NodeInterceptor的子类默认为null
-->
<server protocol="HTTP" host="127.0.0.1" port="6060" root="root" lib="">
<!--
【节点在<server>中唯一】
value: 创建SSLContext的实现类, 可自定义必须是org.redkale.net.SSLCreator的子类
clientauth: true/false/want
keystorepass: KEY密码
keystorefile: KEY文件
truststorepass: TRUST密码
truststorefile: TRUST文件
-->
<ssl creator=""/>
<!--
加载所有的Service服务;
在同一个进程中同一个name同一类型的Service将共用同一个实例
@@ -140,7 +164,7 @@
<service value="com.xxx.XXX2Service" name="" groups="xxx;yyy"/>
<!-- 给Service增加配置属性 -->
<service value="com.xxx.XXX1Service">
<!-- property节点值在 public void init(AnyValue conf) 方法中可以通过 AnyValue properties = conf.getAnyValue("properties");获取 -->
<!-- property值在public void init(AnyValue conf)方法中可以通过AnyValue properties=conf.getAnyValue("properties")获取 -->
<property name="xxxxxx" value="XXXXXXXX"/>
<property name="xxxxxx" value="XXXXXXXX"/>
</service>
@@ -165,7 +189,7 @@
<!-- 给Filter增加配置属性 -->
<filter value="com.xxx.XXX12Filter">
<!-- property节点值在 public void init(AnyValue conf) 方法中可以通过 AnyValue properties = conf.getAnyValue("properties");获取 -->
<!-- property值在public void init(AnyValue conf)方法中可以通过AnyValue properties=conf.getAnyValue("properties")获取 -->
<property name="xxxxxx" value="XXXXXXXX"/>
<property name="xxxxxx" value="XXXXXXXX"/>
</filter>
@@ -207,20 +231,33 @@
<!--
【节点在<server>中唯一】
当Server为HTTP协议时, response节点才有效。
contenttype: plain值为调用finish时的ContentType; 默认值: text/plain; charset=utf-8
json值为调用finishJson时的ContentType; 默认值: application/json; charset=utf-8
defcookie 节点: 当response里输出的cookie没有指定domain 和path时使用该节点的默认值。
如果addheader、setheader 的value值以request.parameters.开头则表示从request.parameters中获取对应的parameter值
如果addheader、setheader 的value值以request.headers.开头则表示从request.headers中获取对应的header值
例如下面例子是在Response输出header时添加两个header一个addHeader 一个setHeader
options 节点: 设置了该节点auto=true当request的method=OPTIONS自动设置addheader、setheader并返回200状态码
options 节点: 设置了该节点auto=true当request的method=OPTIONS自动设置addheader、setheader并返回200状态码
date 节点: 设置了该节点且period有值(单位:毫秒);返回response会包含Date头信息默认为period=0
period=0表示实时获取当前时间;
period<0表示不设置date;
period>0表示定时获取时间; 设置1000表示每秒刷新Date时间
-->
<response>
<contenttype plain="text/plain; charset=utf-8" json="application/json; charset=utf-8"/>
<defcookie domain="" path=""/>
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
<setheader name="Access-Control-Allow-Headers" value="request.headers.Access-Control-Request-Headers"/>
<setheader name="Access-Control-Allow-Credentials" value="true"/>
<options auto="true" />
<date period="0" />
</response>
<!--
【节点在<server>中唯一】
当Server为HTTP协议时render才有效. 指定输出引擎的实现类
value: 输出引擎的实现类, 必须是org.redkale.net.http.HttpRender的子类
-->
<render value="org.redkalex.htel.HttpTemplateRender"/>
<!--
【节点在<server>中唯一】
当Server为HTTP协议时ResourceServlet才有效. 默认存在一个有默认属性的resource-servlet节点

View File

@@ -11,13 +11,15 @@ javax.level = INFO
com.sun.level = INFO
#java.util.logging.FileHandler.level = FINE
#10M
java.util.logging.FileHandler.limit = 10485760
java.util.logging.FileHandler.limit = 20M
java.util.logging.FileHandler.count = 100
java.util.logging.FileHandler.encoding = UTF-8
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%d.log
#java.util.logging.FileHandler.unusual \u5c5e\u6027\u8868\u793a\u5c06 WARNING\u3001SEVERE \u7ea7\u522b\u7684\u65e5\u5fd7\u590d\u5236\u5199\u5165\u5355\u72ec\u7684\u6587\u4ef6\u4e2d
java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-warnerr-%d.log
#\u9700\u8981\u5c4f\u853d\u6d88\u606f\u5185\u5bb9\u7684\u6b63\u5219\u8868\u8fbe\u5f0f
java.util.logging.FileHandler.denyreg =
java.util.logging.FileHandler.append = true
#java.util.logging.ConsoleHandler.level = FINE

View File

@@ -9,7 +9,7 @@
-->
<property name="javax.persistence.datasource" value="org.redkale.source.DataJdbcSource"/>
<!--
是否开启缓存(标记为@Cacheable的Entity类),值目前只支持两种: ALL: 所有开启缓存。 NONE: 关闭所有缓存
是否开启缓存(标记为@Cacheable的Entity类),值目前只支持两种: ALL: 所有开启缓存。 NONE: 关闭所有缓存 非NONE字样统一视为ALL
-->
<property name="javax.persistence.cachemode" value="ALL"/>
@@ -20,12 +20,15 @@
org.mariadb.jdbc.Driver —————— org.mariadb.jdbc.MySQLDataSource
org.postgresql.Driver —————— org.postgresql.ds.PGConnectionPoolDataSource
com.mysql.jdbc.Driver —————— com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
com.mysql.cj.jdbc.Driver —————— com.mysql.cj.jdbc.MysqlConnectionPoolDataSource
oracle.jdbc.driver.OracleDriver —————— oracle.jdbc.pool.OracleConnectionPoolDataSource
com.microsoft.sqlserver.jdbc.SQLServerDriver —————— com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource
org.h2.Driver —————— org.h2.jdbcx.JdbcDataSource
因此 com.mysql.jdbc.Driver 会被自动转换成 com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
并且如果JDBC驱动是以上几个版本javax.persistence.jdbc.driver属性都可以省略Redkale会根据javax.persistence.jdbc.url的值来识别驱动
-->
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.source" value="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource"/>
-->
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="123456"/>
@@ -47,7 +50,6 @@
<properties>
<!-- jdbc:mysql://127.0.0.1:3306/dbim?autoReconnect=true&amp;autoReconnectForPools=true&amp;characterEncoding=utf8 -->
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbim?characterEncoding=utf8"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="123456"/>
</properties>

View File

@@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package javax.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 值越大,优先级越高
*
* @since Common Annotations 1.2
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Priority {
int value();
}

View File

@@ -0,0 +1,32 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package javax.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @since Common Annotations 1.0
*/
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Resource {
public enum AuthenticationType {
CONTAINER,
APPLICATION
}
public String name() default "";
public Class<?> type() default Object.class;
public AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
public boolean shareable() default true;
public String description() default "";
public String mappedName() default "";
public String lookup() default "";
}

View File

@@ -1,63 +0,0 @@
/** *****************************************************************************
* Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Linda DeMichiel - Java Persistence 2.1
* Linda DeMichiel - Java Persistence 2.0
*
***************************************************************************** */
package javax.persistence;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Provides for the specification of generation strategies for the
* values of primary keys.
*
* <p>
* The <code>GeneratedValue</code> annotation
* may be applied to a primary key property or field of an entity or
* mapped superclass in conjunction with the {@link Id} annotation.
* The use of the <code>GeneratedValue</code> annotation is only
* required to be supported for simple primary keys. Use of the
* <code>GeneratedValue</code> annotation is not supported for derived
* primary keys.
*
* <pre>
*
* Example 1:
*
* &#064;Id
* &#064;GeneratedValue(strategy=SEQUENCE, generator="CUST_SEQ")
* &#064;Column(name="CUST_ID")
* public Long getId() { return id; }
*
* Example 2:
*
* &#064;Id
* &#064;GeneratedValue(strategy=TABLE, generator="CUST_GEN")
* &#064;Column(name="CUST_ID")
* Long id;
* </pre>
*
* @see Id
*
* @since Java Persistence 1.0
*/
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface GeneratedValue {
}

View File

@@ -45,7 +45,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* </pre>
*
* @see Column
* @see GeneratedValue
* see GeneratedValue
*
* @since Java Persistence 1.0
*/

34
src/module-info.java Normal file
View File

@@ -0,0 +1,34 @@
/**
* <p>
* see: https://redkale.org
*
* @author zhangjx
*
module org.redkale {
requires java.base;
requires java.logging;
requires java.xml;
requires java.sql;
requires jdk.unsupported; //sun.misc.Unsafe
exports javax.annotation;
exports javax.persistence;
exports org.redkale.boot;
exports org.redkale.boot.watch;
exports org.redkale.convert;
exports org.redkale.convert.bson;
exports org.redkale.convert.ext;
exports org.redkale.convert.json;
exports org.redkale.net;
exports org.redkale.net.http;
exports org.redkale.net.sncp;
exports org.redkale.service;
exports org.redkale.source;
exports org.redkale.util;
exports org.redkale.watch;
}
*/

View File

@@ -0,0 +1,195 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* A visitor to visit a Java annotation. The methods of this class must be
* called in the following order: ( <tt>visit</tt> | <tt>visitEnum</tt> |
* <tt>visitAnnotation</tt> | <tt>visitArray</tt> )* <tt>visitEnd</tt>.
*
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
public abstract class AnnotationVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
protected final int api;
/**
* The annotation visitor to which this visitor must delegate method calls.
* May be null.
*/
protected AnnotationVisitor av;
/**
* Constructs a new {@link AnnotationVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
public AnnotationVisitor(final int api) {
this(api, null);
}
/**
* Constructs a new {@link AnnotationVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param av
* the annotation visitor to which this visitor must delegate
* method calls. May be null.
*/
public AnnotationVisitor(final int api, final AnnotationVisitor av) {
this.api = api;
this.av = av;
}
/**
* Visits a primitive value of the annotation.
*
* @param name
* the value name.
* @param value
* the actual value, whose type must be {@link Byte},
* {@link Boolean}, {@link Character}, {@link Short},
* {@link Integer} , {@link Long}, {@link Float}, {@link Double},
* {@link String} or {@link Type} of OBJECT or ARRAY sort. This
* value can also be an array of byte, boolean, short, char, int,
* long, float or double values (this is equivalent to using
* {@link #visitArray visitArray} and visiting each array element
* in turn, but is more convenient).
*/
public void visit(String name, Object value) {
if (av != null) {
av.visit(name, value);
}
}
/**
* Visits an enumeration value of the annotation.
*
* @param name
* the value name.
* @param desc
* the class descriptor of the enumeration class.
* @param value
* the actual enumeration value.
*/
public void visitEnum(String name, String desc, String value) {
if (av != null) {
av.visitEnum(name, desc, value);
}
}
/**
* Visits a nested annotation value of the annotation.
*
* @param name
* the value name.
* @param desc
* the class descriptor of the nested annotation class.
* @return a visitor to visit the actual nested annotation value, or
* <tt>null</tt> if this visitor is not interested in visiting this
* nested annotation. <i>The nested annotation value must be fully
* visited before calling other methods on this annotation
* visitor</i>.
*/
public AnnotationVisitor visitAnnotation(String name, String desc) {
if (av != null) {
return av.visitAnnotation(name, desc);
}
return null;
}
/**
* Visits an array value of the annotation. Note that arrays of primitive
* types (such as byte, boolean, short, char, int, long, float or double)
* can be passed as value to {@link #visit visit}. This is what
* {@link ClassReader} does.
*
* @param name
* the value name.
* @return a visitor to visit the actual array value elements, or
* <tt>null</tt> if this visitor is not interested in visiting these
* values. The 'name' parameters passed to the methods of this
* visitor are ignored. <i>All the array values must be visited
* before calling other methods on this annotation visitor</i>.
*/
public AnnotationVisitor visitArray(String name) {
if (av != null) {
return av.visitArray(name);
}
return null;
}
/**
* Visits the end of the annotation.
*/
public void visitEnd() {
if (av != null) {
av.visitEnd();
}
}
}

View File

@@ -0,0 +1,400 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* An {@link AnnotationVisitor} that generates annotations in bytecode form.
*
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
final class AnnotationWriter extends AnnotationVisitor {
/**
* The class writer to which this annotation must be added.
*/
private final ClassWriter cw;
/**
* The number of values in this annotation.
*/
private int size;
/**
* <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
* writers used for annotation default and annotation arrays use unnamed
* values.
*/
private final boolean named;
/**
* The annotation values in bytecode form. This byte vector only contains
* the values themselves, i.e. the number of values must be stored as a
* unsigned short just before these bytes.
*/
private final ByteVector bv;
/**
* The byte vector to be used to store the number of values of this
* annotation. See {@link #bv}.
*/
private final ByteVector parent;
/**
* Where the number of values of this annotation must be stored in
* {@link #parent}.
*/
private final int offset;
/**
* Next annotation writer. This field is used to store annotation lists.
*/
AnnotationWriter next;
/**
* Previous annotation writer. This field is used to store annotation lists.
*/
AnnotationWriter prev;
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
/**
* Constructs a new {@link AnnotationWriter}.
*
* @param cw
* the class writer to which this annotation must be added.
* @param named
* <tt>true<tt> if values are named, <tt>false</tt> otherwise.
* @param bv
* where the annotation values must be stored.
* @param parent
* where the number of annotation values must be stored.
* @param offset
* where in <tt>parent</tt> the number of annotation values must
* be stored.
*/
AnnotationWriter(final ClassWriter cw, final boolean named,
final ByteVector bv, final ByteVector parent, final int offset) {
super(Opcodes.ASM6);
this.cw = cw;
this.named = named;
this.bv = bv;
this.parent = parent;
this.offset = offset;
}
// ------------------------------------------------------------------------
// Implementation of the AnnotationVisitor abstract class
// ------------------------------------------------------------------------
@Override
public void visit(final String name, final Object value) {
++size;
if (named) {
bv.putShort(cw.newUTF8(name));
}
if (value instanceof String) {
bv.put12('s', cw.newUTF8((String) value));
} else if (value instanceof Byte) {
bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
} else if (value instanceof Boolean) {
int v = ((Boolean) value).booleanValue() ? 1 : 0;
bv.put12('Z', cw.newInteger(v).index);
} else if (value instanceof Character) {
bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
} else if (value instanceof Short) {
bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
} else if (value instanceof Type) {
bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
} else if (value instanceof byte[]) {
byte[] v = (byte[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) {
bv.put12('B', cw.newInteger(v[i]).index);
}
} else if (value instanceof boolean[]) {
boolean[] v = (boolean[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) {
bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
}
} else if (value instanceof short[]) {
short[] v = (short[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) {
bv.put12('S', cw.newInteger(v[i]).index);
}
} else if (value instanceof char[]) {
char[] v = (char[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) {
bv.put12('C', cw.newInteger(v[i]).index);
}
} else if (value instanceof int[]) {
int[] v = (int[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) {
bv.put12('I', cw.newInteger(v[i]).index);
}
} else if (value instanceof long[]) {
long[] v = (long[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) {
bv.put12('J', cw.newLong(v[i]).index);
}
} else if (value instanceof float[]) {
float[] v = (float[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) {
bv.put12('F', cw.newFloat(v[i]).index);
}
} else if (value instanceof double[]) {
double[] v = (double[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) {
bv.put12('D', cw.newDouble(v[i]).index);
}
} else {
Item i = cw.newConstItem(value);
bv.put12(".s.IFJDCS".charAt(i.type), i.index);
}
}
@Override
public void visitEnum(final String name, final String desc,
final String value) {
++size;
if (named) {
bv.putShort(cw.newUTF8(name));
}
bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
}
@Override
public AnnotationVisitor visitAnnotation(final String name,
final String desc) {
++size;
if (named) {
bv.putShort(cw.newUTF8(name));
}
// write tag and type, and reserve space for values count
bv.put12('@', cw.newUTF8(desc)).putShort(0);
return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
}
@Override
public AnnotationVisitor visitArray(final String name) {
++size;
if (named) {
bv.putShort(cw.newUTF8(name));
}
// write tag, and reserve space for array size
bv.put12('[', 0);
return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
}
@Override
public void visitEnd() {
if (parent != null) {
byte[] data = parent.data;
data[offset] = (byte) (size >>> 8);
data[offset + 1] = (byte) size;
}
}
// ------------------------------------------------------------------------
// Utility methods
// ------------------------------------------------------------------------
/**
* Returns the size of this annotation writer list.
*
* @return the size of this annotation writer list.
*/
int getSize() {
int size = 0;
AnnotationWriter aw = this;
while (aw != null) {
size += aw.bv.length;
aw = aw.next;
}
return size;
}
/**
* Puts the annotations of this annotation writer list into the given byte
* vector.
*
* @param out
* where the annotations must be put.
*/
void put(final ByteVector out) {
int n = 0;
int size = 2;
AnnotationWriter aw = this;
AnnotationWriter last = null;
while (aw != null) {
++n;
size += aw.bv.length;
aw.visitEnd(); // in case user forgot to call visitEnd
aw.prev = last;
last = aw;
aw = aw.next;
}
out.putInt(size);
out.putShort(n);
aw = last;
while (aw != null) {
out.putByteArray(aw.bv.data, 0, aw.bv.length);
aw = aw.prev;
}
}
/**
* Puts the given annotation lists into the given byte vector.
*
* @param panns
* an array of annotation writer lists.
* @param off
* index of the first annotation to be written.
* @param out
* where the annotations must be put.
*/
static void put(final AnnotationWriter[] panns, final int off,
final ByteVector out) {
int size = 1 + 2 * (panns.length - off);
for (int i = off; i < panns.length; ++i) {
size += panns[i] == null ? 0 : panns[i].getSize();
}
out.putInt(size).putByte(panns.length - off);
for (int i = off; i < panns.length; ++i) {
AnnotationWriter aw = panns[i];
AnnotationWriter last = null;
int n = 0;
while (aw != null) {
++n;
aw.visitEnd(); // in case user forgot to call visitEnd
aw.prev = last;
last = aw;
aw = aw.next;
}
out.putShort(n);
aw = last;
while (aw != null) {
out.putByteArray(aw.bv.data, 0, aw.bv.length);
aw = aw.prev;
}
}
}
/**
* Puts the given type reference and type path into the given bytevector.
* LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported.
*
* @param typeRef
* a reference to the annotated type. See {@link TypeReference}.
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param out
* where the type reference and type path must be put.
*/
static void putTarget(int typeRef, TypePath typePath, ByteVector out) {
switch (typeRef >>> 24) {
case 0x00: // CLASS_TYPE_PARAMETER
case 0x01: // METHOD_TYPE_PARAMETER
case 0x16: // METHOD_FORMAL_PARAMETER
out.putShort(typeRef >>> 16);
break;
case 0x13: // FIELD
case 0x14: // METHOD_RETURN
case 0x15: // METHOD_RECEIVER
out.putByte(typeRef >>> 24);
break;
case 0x47: // CAST
case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
out.putInt(typeRef);
break;
// case 0x10: // CLASS_EXTENDS
// case 0x11: // CLASS_TYPE_PARAMETER_BOUND
// case 0x12: // METHOD_TYPE_PARAMETER_BOUND
// case 0x17: // THROWS
// case 0x42: // EXCEPTION_PARAMETER
// case 0x43: // INSTANCEOF
// case 0x44: // NEW
// case 0x45: // CONSTRUCTOR_REFERENCE
// case 0x46: // METHOD_REFERENCE
default:
out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8);
break;
}
if (typePath == null) {
out.putByte(0);
} else {
int length = typePath.b[typePath.offset] * 2 + 1;
out.putByteArray(typePath.b, typePath.offset, length);
}
}
}

View File

@@ -0,0 +1,284 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* A non standard class, field, method or code attribute.
*
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
class Attribute {
/**
* The type of this attribute.
*/
public final String type;
/**
* The raw value of this attribute, used only for unknown attributes.
*/
byte[] value;
/**
* The next attribute in this attribute list. May be <tt>null</tt>.
*/
Attribute next;
/**
* Constructs a new empty attribute.
*
* @param type
* the type of the attribute.
*/
protected Attribute(final String type) {
this.type = type;
}
/**
* Returns <tt>true</tt> if this type of attribute is unknown. The default
* implementation of this method always returns <tt>true</tt>.
*
* @return <tt>true</tt> if this type of attribute is unknown.
*/
public boolean isUnknown() {
return true;
}
/**
* Returns <tt>true</tt> if this type of attribute is a code attribute.
*
* @return <tt>true</tt> if this type of attribute is a code attribute.
*/
public boolean isCodeAttribute() {
return false;
}
/**
* Returns the labels corresponding to this attribute.
*
* @return the labels corresponding to this attribute, or <tt>null</tt> if
* this attribute is not a code attribute that contains labels.
*/
protected Label[] getLabels() {
return null;
}
/**
* Reads a {@link #type type} attribute. This method must return a
* <i>new</i> {@link Attribute} object, of type {@link #type type},
* corresponding to the <tt>len</tt> bytes starting at the given offset, in
* the given class reader.
*
* @param cr
* the class that contains the attribute to be read.
* @param off
* index of the first byte of the attribute's content in
* {@link ClassReader#b cr.b}. The 6 attribute header bytes,
* containing the type and the length of the attribute, are not
* taken into account here.
* @param len
* the length of the attribute's content.
* @param buf
* buffer to be used to call {@link ClassReader#readUTF8
* readUTF8}, {@link ClassReader#readClass(int,char[]) readClass}
* or {@link ClassReader#readConst readConst}.
* @param codeOff
* index of the first byte of code's attribute content in
* {@link ClassReader#b cr.b}, or -1 if the attribute to be read
* is not a code attribute. The 6 attribute header bytes,
* containing the type and the length of the attribute, are not
* taken into account here.
* @param labels
* the labels of the method's code, or <tt>null</tt> if the
* attribute to be read is not a code attribute.
* @return a <i>new</i> {@link Attribute} object corresponding to the given
* bytes.
*/
protected Attribute read(final ClassReader cr, final int off,
final int len, final char[] buf, final int codeOff,
final Label[] labels) {
Attribute attr = new Attribute(type);
attr.value = new byte[len];
System.arraycopy(cr.b, off, attr.value, 0, len);
return attr;
}
/**
* Returns the byte array form of this attribute.
*
* @param cw
* the class to which this attribute must be added. This
* parameter can be used to add to the constant pool of this
* class the items that corresponds to this attribute.
* @param code
* the bytecode of the method corresponding to this code
* attribute, or <tt>null</tt> if this attribute is not a code
* attributes.
* @param len
* the length of the bytecode of the method corresponding to this
* code attribute, or <tt>null</tt> if this attribute is not a
* code attribute.
* @param maxStack
* the maximum stack size of the method corresponding to this
* code attribute, or -1 if this attribute is not a code
* attribute.
* @param maxLocals
* the maximum number of local variables of the method
* corresponding to this code attribute, or -1 if this attribute
* is not a code attribute.
* @return the byte array form of this attribute.
*/
protected ByteVector write(final ClassWriter cw, final byte[] code,
final int len, final int maxStack, final int maxLocals) {
ByteVector v = new ByteVector();
v.data = value;
v.length = value.length;
return v;
}
/**
* Returns the length of the attribute list that begins with this attribute.
*
* @return the length of the attribute list that begins with this attribute.
*/
final int getCount() {
int count = 0;
Attribute attr = this;
while (attr != null) {
count += 1;
attr = attr.next;
}
return count;
}
/**
* Returns the size of all the attributes in this attribute list.
*
* @param cw
* the class writer to be used to convert the attributes into
* byte arrays, with the {@link #write write} method.
* @param code
* the bytecode of the method corresponding to these code
* attributes, or <tt>null</tt> if these attributes are not code
* attributes.
* @param len
* the length of the bytecode of the method corresponding to
* these code attributes, or <tt>null</tt> if these attributes
* are not code attributes.
* @param maxStack
* the maximum stack size of the method corresponding to these
* code attributes, or -1 if these attributes are not code
* attributes.
* @param maxLocals
* the maximum number of local variables of the method
* corresponding to these code attributes, or -1 if these
* attributes are not code attributes.
* @return the size of all the attributes in this attribute list. This size
* includes the size of the attribute headers.
*/
final int getSize(final ClassWriter cw, final byte[] code, final int len,
final int maxStack, final int maxLocals) {
Attribute attr = this;
int size = 0;
while (attr != null) {
cw.newUTF8(attr.type);
size += attr.write(cw, code, len, maxStack, maxLocals).length + 6;
attr = attr.next;
}
return size;
}
/**
* Writes all the attributes of this attribute list in the given byte
* vector.
*
* @param cw
* the class writer to be used to convert the attributes into
* byte arrays, with the {@link #write write} method.
* @param code
* the bytecode of the method corresponding to these code
* attributes, or <tt>null</tt> if these attributes are not code
* attributes.
* @param len
* the length of the bytecode of the method corresponding to
* these code attributes, or <tt>null</tt> if these attributes
* are not code attributes.
* @param maxStack
* the maximum stack size of the method corresponding to these
* code attributes, or -1 if these attributes are not code
* attributes.
* @param maxLocals
* the maximum number of local variables of the method
* corresponding to these code attributes, or -1 if these
* attributes are not code attributes.
* @param out
* where the attributes must be written.
*/
final void put(final ClassWriter cw, final byte[] code, final int len,
final int maxStack, final int maxLocals, final ByteVector out) {
Attribute attr = this;
while (attr != null) {
ByteVector b = attr.write(cw, code, len, maxStack, maxLocals);
out.putShort(cw.newUTF8(attr.type)).putInt(b.length);
out.putByteArray(b.data, 0, b.length);
attr = attr.next;
}
}
}

View File

@@ -0,0 +1,368 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* A dynamically extensible vector of bytes. This class is roughly equivalent to
* a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient.
*
* @author Eric Bruneton
*/
public class ByteVector {
/**
* The content of this vector.
*/
byte[] data;
/**
* Actual number of bytes in this vector.
*/
int length;
/**
* Constructs a new {@link ByteVector ByteVector} with a default initial
* size.
*/
public ByteVector() {
data = new byte[64];
}
/**
* Constructs a new {@link ByteVector ByteVector} with the given initial
* size.
*
* @param initialSize
* the initial size of the byte vector to be constructed.
*/
public ByteVector(final int initialSize) {
data = new byte[initialSize];
}
/**
* Puts a byte into this byte vector. The byte vector is automatically
* enlarged if necessary.
*
* @param b
* a byte.
* @return this byte vector.
*/
public ByteVector putByte(final int b) {
int length = this.length;
if (length + 1 > data.length) {
enlarge(1);
}
data[length++] = (byte) b;
this.length = length;
return this;
}
/**
* Puts two bytes into this byte vector. The byte vector is automatically
* enlarged if necessary.
*
* @param b1
* a byte.
* @param b2
* another byte.
* @return this byte vector.
*/
ByteVector put11(final int b1, final int b2) {
int length = this.length;
if (length + 2 > data.length) {
enlarge(2);
}
byte[] data = this.data;
data[length++] = (byte) b1;
data[length++] = (byte) b2;
this.length = length;
return this;
}
/**
* Puts a short into this byte vector. The byte vector is automatically
* enlarged if necessary.
*
* @param s
* a short.
* @return this byte vector.
*/
public ByteVector putShort(final int s) {
int length = this.length;
if (length + 2 > data.length) {
enlarge(2);
}
byte[] data = this.data;
data[length++] = (byte) (s >>> 8);
data[length++] = (byte) s;
this.length = length;
return this;
}
/**
* Puts a byte and a short into this byte vector. The byte vector is
* automatically enlarged if necessary.
*
* @param b
* a byte.
* @param s
* a short.
* @return this byte vector.
*/
ByteVector put12(final int b, final int s) {
int length = this.length;
if (length + 3 > data.length) {
enlarge(3);
}
byte[] data = this.data;
data[length++] = (byte) b;
data[length++] = (byte) (s >>> 8);
data[length++] = (byte) s;
this.length = length;
return this;
}
/**
* Puts an int into this byte vector. The byte vector is automatically
* enlarged if necessary.
*
* @param i
* an int.
* @return this byte vector.
*/
public ByteVector putInt(final int i) {
int length = this.length;
if (length + 4 > data.length) {
enlarge(4);
}
byte[] data = this.data;
data[length++] = (byte) (i >>> 24);
data[length++] = (byte) (i >>> 16);
data[length++] = (byte) (i >>> 8);
data[length++] = (byte) i;
this.length = length;
return this;
}
/**
* Puts a long into this byte vector. The byte vector is automatically
* enlarged if necessary.
*
* @param l
* a long.
* @return this byte vector.
*/
public ByteVector putLong(final long l) {
int length = this.length;
if (length + 8 > data.length) {
enlarge(8);
}
byte[] data = this.data;
int i = (int) (l >>> 32);
data[length++] = (byte) (i >>> 24);
data[length++] = (byte) (i >>> 16);
data[length++] = (byte) (i >>> 8);
data[length++] = (byte) i;
i = (int) l;
data[length++] = (byte) (i >>> 24);
data[length++] = (byte) (i >>> 16);
data[length++] = (byte) (i >>> 8);
data[length++] = (byte) i;
this.length = length;
return this;
}
/**
* Puts an UTF8 string into this byte vector. The byte vector is
* automatically enlarged if necessary.
*
* @param s
* a String whose UTF8 encoded length must be less than 65536.
* @return this byte vector.
*/
public ByteVector putUTF8(final String s) {
int charLength = s.length();
if (charLength > 65535) {
throw new IllegalArgumentException();
}
int len = length;
if (len + 2 + charLength > data.length) {
enlarge(2 + charLength);
}
byte[] data = this.data;
// optimistic algorithm: instead of computing the byte length and then
// serializing the string (which requires two loops), we assume the byte
// length is equal to char length (which is the most frequent case), and
// we start serializing the string right away. During the serialization,
// if we find that this assumption is wrong, we continue with the
// general method.
data[len++] = (byte) (charLength >>> 8);
data[len++] = (byte) charLength;
for (int i = 0; i < charLength; ++i) {
char c = s.charAt(i);
if (c >= '\001' && c <= '\177') {
data[len++] = (byte) c;
} else {
length = len;
return encodeUTF8(s, i, 65535);
}
}
length = len;
return this;
}
/**
* Puts an UTF8 string into this byte vector. The byte vector is
* automatically enlarged if necessary. The string length is encoded in two
* bytes before the encoded characters, if there is space for that (i.e. if
* this.length - i - 2 >= 0).
*
* @param s
* the String to encode.
* @param i
* the index of the first character to encode. The previous
* characters are supposed to have already been encoded, using
* only one byte per character.
* @param maxByteLength
* the maximum byte length of the encoded string, including the
* already encoded characters.
* @return this byte vector.
*/
ByteVector encodeUTF8(final String s, int i, int maxByteLength) {
int charLength = s.length();
int byteLength = i;
char c;
for (int j = i; j < charLength; ++j) {
c = s.charAt(j);
if (c >= '\001' && c <= '\177') {
byteLength++;
} else if (c > '\u07FF') {
byteLength += 3;
} else {
byteLength += 2;
}
}
if (byteLength > maxByteLength) {
throw new IllegalArgumentException();
}
int start = length - i - 2;
if (start >= 0) {
data[start] = (byte) (byteLength >>> 8);
data[start + 1] = (byte) byteLength;
}
if (length + byteLength - i > data.length) {
enlarge(byteLength - i);
}
int len = length;
for (int j = i; j < charLength; ++j) {
c = s.charAt(j);
if (c >= '\001' && c <= '\177') {
data[len++] = (byte) c;
} else if (c > '\u07FF') {
data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
data[len++] = (byte) (0x80 | c & 0x3F);
} else {
data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
data[len++] = (byte) (0x80 | c & 0x3F);
}
}
length = len;
return this;
}
/**
* Puts an array of bytes into this byte vector. The byte vector is
* automatically enlarged if necessary.
*
* @param b
* an array of bytes. May be <tt>null</tt> to put <tt>len</tt>
* null bytes into this byte vector.
* @param off
* index of the fist byte of b that must be copied.
* @param len
* number of bytes of b that must be copied.
* @return this byte vector.
*/
public ByteVector putByteArray(final byte[] b, final int off, final int len) {
if (length + len > data.length) {
enlarge(len);
}
if (b != null) {
System.arraycopy(b, off, data, length, len);
}
length += len;
return this;
}
/**
* Enlarge this byte vector so that it can receive n more bytes.
*
* @param size
* number of additional bytes that this byte vector should be
* able to receive.
*/
private void enlarge(final int size) {
int length1 = 2 * data.length;
int length2 = length + size;
byte[] newData = new byte[length1 > length2 ? length1 : length2];
System.arraycopy(data, 0, newData, 0, length);
data = newData;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,365 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* A visitor to visit a Java class. The methods of this class must be called in
* the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [
* <tt>visitModule</tt> ][ <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> |
* <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* (
* <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> )*
* <tt>visitEnd</tt>.
*
* @author Eric Bruneton
*/
public abstract class ClassVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
protected final int api;
/**
* The class visitor to which this visitor must delegate method calls. May
* be null.
*/
protected ClassVisitor cv;
/**
* Constructs a new {@link ClassVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
public ClassVisitor(final int api) {
this(api, null);
}
/**
* Constructs a new {@link ClassVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param cv
* the class visitor to which this visitor must delegate method
* calls. May be null.
*/
public ClassVisitor(final int api, final ClassVisitor cv) {
this.api = api;
this.cv = cv;
}
/**
* Visits the header of the class.
*
* @param version
* the class version.
* @param access
* the class's access flags (see {@link Opcodes}). This parameter
* also indicates if the class is deprecated.
* @param name
* the internal name of the class (see
* {@link Type#getInternalName() getInternalName}).
* @param signature
* the signature of this class. May be <tt>null</tt> if the class
* is not a generic one, and does not extend or implement generic
* classes or interfaces.
* @param superName
* the internal of name of the super class (see
* {@link Type#getInternalName() getInternalName}). For
* interfaces, the super class is {@link Object}. May be
* <tt>null</tt>, but only for the {@link Object} class.
* @param interfaces
* the internal names of the class's interfaces (see
* {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
*/
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
if (cv != null) {
cv.visit(version, access, name, signature, superName, interfaces);
}
}
/**
* Visits the source of the class.
*
* @param source
* the name of the source file from which the class was compiled.
* May be <tt>null</tt>.
* @param debug
* additional debug information to compute the correspondance
* between source and compiled elements of the class. May be
* <tt>null</tt>.
*/
public void visitSource(String source, String debug) {
if (cv != null) {
cv.visitSource(source, debug);
}
}
/**
* Visit the module corresponding to the class.
* @param name
* module name
* @param access
* module flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC}
* and {@code ACC_MANDATED}.
* @param version
* module version or null.
* @return a visitor to visit the module values, or <tt>null</tt> if
* this visitor is not interested in visiting this module.
*/
public ModuleVisitor visitModule(String name, int access, String version) {
if (api < Opcodes.ASM6) {
throw new RuntimeException();
}
if (cv != null) {
return cv.visitModule(name, access, version);
}
return null;
}
/**
* Visits the enclosing class of the class. This method must be called only
* if the class has an enclosing class.
*
* @param owner
* internal name of the enclosing class of the class.
* @param name
* the name of the method that contains the class, or
* <tt>null</tt> if the class is not enclosed in a method of its
* enclosing class.
* @param desc
* the descriptor of the method that contains the class, or
* <tt>null</tt> if the class is not enclosed in a method of its
* enclosing class.
*/
public void visitOuterClass(String owner, String name, String desc) {
if (cv != null) {
cv.visitOuterClass(owner, name, desc);
}
}
/**
* Visits an annotation of the class.
*
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (cv != null) {
return cv.visitAnnotation(desc, visible);
}
return null;
}
/**
* Visits an annotation on a type in the class signature.
*
* @param typeRef
* a reference to the annotated type. The sort of this type
* reference must be {@link TypeReference#CLASS_TYPE_PARAMETER
* CLASS_TYPE_PARAMETER},
* {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND
* CLASS_TYPE_PARAMETER_BOUND} or
* {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See
* {@link TypeReference}.
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
if (cv != null) {
return cv.visitTypeAnnotation(typeRef, typePath, desc, visible);
}
return null;
}
/**
* Visits a non standard attribute of the class.
*
* @param attr
* an attribute.
*/
public void visitAttribute(Attribute attr) {
if (cv != null) {
cv.visitAttribute(attr);
}
}
/**
* Visits information about an inner class. This inner class is not
* necessarily a member of the class being visited.
*
* @param name
* the internal name of an inner class (see
* {@link Type#getInternalName() getInternalName}).
* @param outerName
* the internal name of the class to which the inner class
* belongs (see {@link Type#getInternalName() getInternalName}).
* May be <tt>null</tt> for not member classes.
* @param innerName
* the (simple) name of the inner class inside its enclosing
* class. May be <tt>null</tt> for anonymous inner classes.
* @param access
* the access flags of the inner class as originally declared in
* the enclosing class.
*/
public void visitInnerClass(String name, String outerName,
String innerName, int access) {
if (cv != null) {
cv.visitInnerClass(name, outerName, innerName, access);
}
}
/**
* Visits a field of the class.
*
* @param access
* the field's access flags (see {@link Opcodes}). This parameter
* also indicates if the field is synthetic and/or deprecated.
* @param name
* the field's name.
* @param desc
* the field's descriptor (see {@link Type Type}).
* @param signature
* the field's signature. May be <tt>null</tt> if the field's
* type does not use generic types.
* @param value
* the field's initial value. This parameter, which may be
* <tt>null</tt> if the field does not have an initial value,
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double} or a {@link String} (for <tt>int</tt>,
* <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields
* respectively). <i>This parameter is only used for static
* fields</i>. Its value is ignored for non static fields, which
* must be initialized through bytecode instructions in
* constructors or methods.
* @return a visitor to visit field annotations and attributes, or
* <tt>null</tt> if this class visitor is not interested in visiting
* these annotations and attributes.
*/
public FieldVisitor visitField(int access, String name, String desc,
String signature, Object value) {
if (cv != null) {
return cv.visitField(access, name, desc, signature, value);
}
return null;
}
/**
* Visits a method of the class. This method <i>must</i> return a new
* {@link MethodVisitor} instance (or <tt>null</tt>) each time it is called,
* i.e., it should not return a previously returned visitor.
*
* @param access
* the method's access flags (see {@link Opcodes}). This
* parameter also indicates if the method is synthetic and/or
* deprecated.
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link Type Type}).
* @param signature
* the method's signature. May be <tt>null</tt> if the method
* parameters, return type and exceptions do not use generic
* types.
* @param exceptions
* the internal names of the method's exception classes (see
* {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
* @return an object to visit the byte code of the method, or <tt>null</tt>
* if this class visitor is not interested in visiting the code of
* this method.
*/
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
if (cv != null) {
return cv.visitMethod(access, name, desc, signature, exceptions);
}
return null;
}
/**
* Visits the end of the class. This method, which is the last one to be
* called, is used to inform the visitor that all the fields and methods of
* the class have been visited.
*/
public void visitEnd() {
if (cv != null) {
cv.visitEnd();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,174 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* Information about a class being parsed in a {@link ClassReader}.
*
* @author Eric Bruneton
*/
class Context {
/**
* Prototypes of the attributes that must be parsed for this class.
*/
Attribute[] attrs;
/**
* The {@link ClassReader} option flags for the parsing of this class.
*/
int flags;
/**
* The buffer used to read strings.
*/
char[] buffer;
/**
* The start index of each bootstrap method.
*/
int[] bootstrapMethods;
/**
* The access flags of the method currently being parsed.
*/
int access;
/**
* The name of the method currently being parsed.
*/
String name;
/**
* The descriptor of the method currently being parsed.
*/
String desc;
/**
* The label objects, indexed by bytecode offset, of the method currently
* being parsed (only bytecode offsets for which a label is needed have a
* non null associated Label object).
*/
Label[] labels;
/**
* The target of the type annotation currently being parsed.
*/
int typeRef;
/**
* The path of the type annotation currently being parsed.
*/
TypePath typePath;
/**
* The offset of the latest stack map frame that has been parsed.
*/
int offset;
/**
* The labels corresponding to the start of the local variable ranges in the
* local variable type annotation currently being parsed.
*/
Label[] start;
/**
* The labels corresponding to the end of the local variable ranges in the
* local variable type annotation currently being parsed.
*/
Label[] end;
/**
* The local variable indices for each local variable range in the local
* variable type annotation currently being parsed.
*/
int[] index;
/**
* The encoding of the latest stack map frame that has been parsed.
*/
int mode;
/**
* The number of locals in the latest stack map frame that has been parsed.
*/
int localCount;
/**
* The number locals in the latest stack map frame that has been parsed,
* minus the number of locals in the previous frame.
*/
int localDiff;
/**
* The local values of the latest stack map frame that has been parsed.
*/
Object[] local;
/**
* The stack size of the latest stack map frame that has been parsed.
*/
int stackCount;
/**
* The stack values of the latest stack map frame that has been parsed.
*/
Object[] stack;
}

View File

@@ -0,0 +1,85 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* Information about the input stack map frame at the "current" instruction of a
* method. This is implemented as a Frame subclass for a "basic block"
* containing only one instruction.
*
* @author Eric Bruneton
*/
class CurrentFrame extends Frame {
/**
* Sets this CurrentFrame to the input stack map frame of the next "current"
* instruction, i.e. the instruction just after the given one. It is assumed
* that the value of this object when this method is called is the stack map
* frame status just before the given instruction is executed.
*/
@Override
void execute(int opcode, int arg, ClassWriter cw, Item item) {
super.execute(opcode, arg, cw, item);
Frame successor = new Frame();
merge(cw, successor, 0);
set(successor);
owner.inputStackTop = 0;
}
}

View File

@@ -0,0 +1,104 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* An edge in the control flow graph of a method body. See {@link Label Label}.
*
* @author Eric Bruneton
*/
class Edge {
/**
* Denotes a normal control flow graph edge.
*/
static final int NORMAL = 0;
/**
* Denotes a control flow graph edge corresponding to an exception handler.
* More precisely any {@link Edge} whose {@link #info} is strictly positive
* corresponds to an exception handler. The actual value of {@link #info} is
* the index, in the {@link ClassWriter} type table, of the exception that
* is catched.
*/
static final int EXCEPTION = 0x7FFFFFFF;
/**
* Information about this control flow graph edge. If
* {@link ClassWriter#COMPUTE_MAXS} is used this field is the (relative)
* stack size in the basic block from which this edge originates. This size
* is equal to the stack size at the "jump" instruction to which this edge
* corresponds, relatively to the stack size at the beginning of the
* originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used,
* this field is the kind of this control flow graph edge (i.e. NORMAL or
* EXCEPTION).
*/
int info;
/**
* The successor block of the basic block from which this edge originates.
*/
Label successor;
/**
* The next edge in the list of successors of the originating basic block.
* See {@link Label#successors successors}.
*/
Edge next;
}

View File

@@ -0,0 +1,173 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* A visitor to visit a Java field. The methods of this class must be called in
* the following order: ( <tt>visitAnnotation</tt> |
* <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* <tt>visitEnd</tt>.
*
* @author Eric Bruneton
*/
public abstract class FieldVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
protected final int api;
/**
* The field visitor to which this visitor must delegate method calls. May
* be null.
*/
protected FieldVisitor fv;
/**
* Constructs a new {@link FieldVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
public FieldVisitor(final int api) {
this(api, null);
}
/**
* Constructs a new {@link FieldVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param fv
* the field visitor to which this visitor must delegate method
* calls. May be null.
*/
public FieldVisitor(final int api, final FieldVisitor fv) {
this.api = api;
this.fv = fv;
}
/**
* Visits an annotation of the field.
*
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (fv != null) {
return fv.visitAnnotation(desc, visible);
}
return null;
}
/**
* Visits an annotation on the type of the field.
*
* @param typeRef
* a reference to the annotated type. The sort of this type
* reference must be {@link TypeReference#FIELD FIELD}. See
* {@link TypeReference}.
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
if (fv != null) {
return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
}
return null;
}
/**
* Visits a non standard attribute of the field.
*
* @param attr
* an attribute.
*/
public void visitAttribute(Attribute attr) {
if (fv != null) {
fv.visitAttribute(attr);
}
}
/**
* Visits the end of the field. This method, which is the last one to be
* called, is used to inform the visitor that all the annotations and
* attributes of the field have been visited.
*/
public void visitEnd() {
if (fv != null) {
fv.visitEnd();
}
}
}

View File

@@ -0,0 +1,352 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* An {@link FieldVisitor} that generates Java fields in bytecode form.
*
* @author Eric Bruneton
*/
final class FieldWriter extends FieldVisitor {
/**
* The class writer to which this field must be added.
*/
private final ClassWriter cw;
/**
* Access flags of this field.
*/
private final int access;
/**
* The index of the constant pool item that contains the name of this
* method.
*/
private final int name;
/**
* The index of the constant pool item that contains the descriptor of this
* field.
*/
private final int desc;
/**
* The index of the constant pool item that contains the signature of this
* field.
*/
private int signature;
/**
* The index of the constant pool item that contains the constant value of
* this field.
*/
private int value;
/**
* The runtime visible annotations of this field. May be <tt>null</tt>.
*/
private AnnotationWriter anns;
/**
* The runtime invisible annotations of this field. May be <tt>null</tt>.
*/
private AnnotationWriter ianns;
/**
* The runtime visible type annotations of this field. May be <tt>null</tt>.
*/
private AnnotationWriter tanns;
/**
* The runtime invisible type annotations of this field. May be
* <tt>null</tt>.
*/
private AnnotationWriter itanns;
/**
* The non standard attributes of this field. May be <tt>null</tt>.
*/
private Attribute attrs;
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
/**
* Constructs a new {@link FieldWriter}.
*
* @param cw
* the class writer to which this field must be added.
* @param access
* the field's access flags (see {@link Opcodes}).
* @param name
* the field's name.
* @param desc
* the field's descriptor (see {@link Type}).
* @param signature
* the field's signature. May be <tt>null</tt>.
* @param value
* the field's constant value. May be <tt>null</tt>.
*/
FieldWriter(final ClassWriter cw, final int access, final String name,
final String desc, final String signature, final Object value) {
super(Opcodes.ASM6);
if (cw.firstField == null) {
cw.firstField = this;
} else {
cw.lastField.fv = this;
}
cw.lastField = this;
this.cw = cw;
this.access = access;
this.name = cw.newUTF8(name);
this.desc = cw.newUTF8(desc);
if (signature != null) {
this.signature = cw.newUTF8(signature);
}
if (value != null) {
this.value = cw.newConstItem(value).index;
}
}
// ------------------------------------------------------------------------
// Implementation of the FieldVisitor abstract class
// ------------------------------------------------------------------------
@Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
ByteVector bv = new ByteVector();
// write type, and reserve space for values count
bv.putShort(cw.newUTF8(desc)).putShort(0);
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
if (visible) {
aw.next = anns;
anns = aw;
} else {
aw.next = ianns;
ianns = aw;
}
return aw;
}
@Override
public AnnotationVisitor visitTypeAnnotation(final int typeRef,
final TypePath typePath, final String desc, final boolean visible) {
ByteVector bv = new ByteVector();
// write target_type and target_info
AnnotationWriter.putTarget(typeRef, typePath, bv);
// write type, and reserve space for values count
bv.putShort(cw.newUTF8(desc)).putShort(0);
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
bv.length - 2);
if (visible) {
aw.next = tanns;
tanns = aw;
} else {
aw.next = itanns;
itanns = aw;
}
return aw;
}
@Override
public void visitAttribute(final Attribute attr) {
attr.next = attrs;
attrs = attr;
}
@Override
public void visitEnd() {
}
// ------------------------------------------------------------------------
// Utility methods
// ------------------------------------------------------------------------
/**
* Returns the size of this field.
*
* @return the size of this field.
*/
int getSize() {
int size = 8;
if (value != 0) {
cw.newUTF8("ConstantValue");
size += 8;
}
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
if ((cw.version & 0xFFFF) < Opcodes.V1_5
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
cw.newUTF8("Synthetic");
size += 6;
}
}
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
cw.newUTF8("Deprecated");
size += 6;
}
if (signature != 0) {
cw.newUTF8("Signature");
size += 8;
}
if (anns != null) {
cw.newUTF8("RuntimeVisibleAnnotations");
size += 8 + anns.getSize();
}
if (ianns != null) {
cw.newUTF8("RuntimeInvisibleAnnotations");
size += 8 + ianns.getSize();
}
if (tanns != null) {
cw.newUTF8("RuntimeVisibleTypeAnnotations");
size += 8 + tanns.getSize();
}
if (itanns != null) {
cw.newUTF8("RuntimeInvisibleTypeAnnotations");
size += 8 + itanns.getSize();
}
if (attrs != null) {
size += attrs.getSize(cw, null, 0, -1, -1);
}
return size;
}
/**
* Puts the content of this field into the given byte vector.
*
* @param out
* where the content of this field must be put.
*/
void put(final ByteVector out) {
final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
| ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
out.putShort(access & ~mask).putShort(name).putShort(desc);
int attributeCount = 0;
if (value != 0) {
++attributeCount;
}
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
if ((cw.version & 0xFFFF) < Opcodes.V1_5
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
++attributeCount;
}
}
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
++attributeCount;
}
if (signature != 0) {
++attributeCount;
}
if (anns != null) {
++attributeCount;
}
if (ianns != null) {
++attributeCount;
}
if (tanns != null) {
++attributeCount;
}
if (itanns != null) {
++attributeCount;
}
if (attrs != null) {
attributeCount += attrs.getCount();
}
out.putShort(attributeCount);
if (value != 0) {
out.putShort(cw.newUTF8("ConstantValue"));
out.putInt(2).putShort(value);
}
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
if ((cw.version & 0xFFFF) < Opcodes.V1_5
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
out.putShort(cw.newUTF8("Synthetic")).putInt(0);
}
}
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
out.putShort(cw.newUTF8("Deprecated")).putInt(0);
}
if (signature != 0) {
out.putShort(cw.newUTF8("Signature"));
out.putInt(2).putShort(signature);
}
if (anns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
anns.put(out);
}
if (ianns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out);
}
if (tanns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
tanns.put(out);
}
if (itanns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
itanns.put(out);
}
if (attrs != null) {
attrs.put(cw, null, 0, -1, -1, out);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,223 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* A reference to a field or a method.
*
* @author Remi Forax
* @author Eric Bruneton
*/
public final class Handle {
/**
* The kind of field or method designated by this Handle. Should be
* {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}.
*/
final int tag;
/**
* The internal name of the class that owns the field or method designated
* by this handle.
*/
final String owner;
/**
* The name of the field or method designated by this handle.
*/
final String name;
/**
* The descriptor of the field or method designated by this handle.
*/
final String desc;
/**
* Indicate if the owner is an interface or not.
*/
final boolean itf;
/**
* Constructs a new field or method handle.
*
* @param tag
* the kind of field or method designated by this Handle. Must be
* {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
* {@link Opcodes#H_INVOKEVIRTUAL},
* {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}.
* @param owner
* the internal name of the class that owns the field or method
* designated by this handle.
* @param name
* the name of the field or method designated by this handle.
* @param desc
* the descriptor of the field or method designated by this
* handle.
* @param itf
* true if the owner is an interface.
*/
public Handle(int tag, String owner, String name, String desc, boolean itf) {
this.tag = tag;
this.owner = owner;
this.name = name;
this.desc = desc;
this.itf = itf;
}
/**
* Returns the kind of field or method designated by this handle.
*
* @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}.
*/
public int getTag() {
return tag;
}
/**
* Returns the internal name of the class that owns the field or method
* designated by this handle.
*
* @return the internal name of the class that owns the field or method
* designated by this handle.
*/
public String getOwner() {
return owner;
}
/**
* Returns the name of the field or method designated by this handle.
*
* @return the name of the field or method designated by this handle.
*/
public String getName() {
return name;
}
/**
* Returns the descriptor of the field or method designated by this handle.
*
* @return the descriptor of the field or method designated by this handle.
*/
public String getDesc() {
return desc;
}
/**
* Returns true if the owner of the field or method designated
* by this handle is an interface.
*
* @return true if the owner of the field or method designated
* by this handle is an interface.
*/
public boolean isInterface() {
return itf;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Handle)) {
return false;
}
Handle h = (Handle) obj;
return tag == h.tag && itf == h.itf && owner.equals(h.owner)
&& name.equals(h.name) && desc.equals(h.desc);
}
@Override
public int hashCode() {
return tag + (itf? 64: 0) + owner.hashCode() * name.hashCode() * desc.hashCode();
}
/**
* Returns the textual representation of this handle. The textual
* representation is:
*
* <pre>
* for a reference to a class:
* owner '.' name desc ' ' '(' tag ')'
* for a reference to an interface:
* owner '.' name desc ' ' '(' tag ' ' itf ')'
* </pre>
*
* . As this format is unambiguous, it can be parsed if necessary.
*/
@Override
public String toString() {
return owner + '.' + name + desc + " (" + tag + (itf? " itf": "") + ')';
}
}

View File

@@ -0,0 +1,150 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* Information about an exception handler block.
*
* @author Eric Bruneton
*/
class Handler {
/**
* Beginning of the exception handler's scope (inclusive).
*/
Label start;
/**
* End of the exception handler's scope (exclusive).
*/
Label end;
/**
* Beginning of the exception handler's code.
*/
Label handler;
/**
* Internal name of the type of exceptions handled by this handler, or
* <tt>null</tt> to catch any exceptions.
*/
String desc;
/**
* Constant pool index of the internal name of the type of exceptions
* handled by this handler, or 0 to catch any exceptions.
*/
int type;
/**
* Next exception handler block info.
*/
Handler next;
/**
* Removes the range between start and end from the given exception
* handlers.
*
* @param h
* an exception handler list.
* @param start
* the start of the range to be removed.
* @param end
* the end of the range to be removed. Maybe null.
* @return the exception handler list with the start-end range removed.
*/
static Handler remove(Handler h, Label start, Label end) {
if (h == null) {
return null;
} else {
h.next = remove(h.next, start, end);
}
int hstart = h.start.position;
int hend = h.end.position;
int s = start.position;
int e = end == null ? Integer.MAX_VALUE : end.position;
// if [hstart,hend[ and [s,e[ intervals intersect...
if (s < hend && e > hstart) {
if (s <= hstart) {
if (e >= hend) {
// [hstart,hend[ fully included in [s,e[, h removed
h = h.next;
} else {
// [hstart,hend[ minus [s,e[ = [e,hend[
h.start = end;
}
} else if (e >= hend) {
// [hstart,hend[ minus [s,e[ = [hstart,s[
h.end = start;
} else {
// [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[
Handler g = new Handler();
g.start = end;
g.end = h.end;
g.handler = h.handler;
g.desc = h.desc;
g.type = h.type;
g.next = h.next;
h.end = start;
h.next = g;
}
}
return h;
}
}

View File

@@ -0,0 +1,347 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* A constant pool item. Constant pool items can be created with the 'newXXX'
* methods in the {@link ClassWriter} class.
*
* @author Eric Bruneton
*/
final class Item {
/**
* Index of this item in the constant pool.
*/
int index;
/**
* Type of this constant pool item. A single class is used to represent all
* constant pool item types, in order to minimize the bytecode size of this
* package. The value of this field is one of {@link ClassWriter#INT},
* {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT},
* {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8},
* {@link ClassWriter#STR}, {@link ClassWriter#CLASS},
* {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD},
* {@link ClassWriter#METH}, {@link ClassWriter#IMETH},
* {@link ClassWriter#MODULE}, {@link ClassWriter#PACKAGE},
* {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}.
*
* MethodHandle constant 9 variations are stored using a range of 9 values
* from {@link ClassWriter#HANDLE_BASE} + 1 to
* {@link ClassWriter#HANDLE_BASE} + 9.
*
* Special Item types are used for Items that are stored in the ClassWriter
* {@link ClassWriter#typeTable}, instead of the constant pool, in order to
* avoid clashes with normal constant pool items in the ClassWriter constant
* pool's hash table. These special item types are
* {@link ClassWriter#TYPE_NORMAL}, {@link ClassWriter#TYPE_UNINIT} and
* {@link ClassWriter#TYPE_MERGED}.
*/
int type;
/**
* Value of this item, for an integer item.
*/
int intVal;
/**
* Value of this item, for a long item.
*/
long longVal;
/**
* First part of the value of this item, for items that do not hold a
* primitive value.
*/
String strVal1;
/**
* Second part of the value of this item, for items that do not hold a
* primitive value.
*/
String strVal2;
/**
* Third part of the value of this item, for items that do not hold a
* primitive value.
*/
String strVal3;
/**
* The hash code value of this constant pool item.
*/
int hashCode;
/**
* Link to another constant pool item, used for collision lists in the
* constant pool's hash table.
*/
Item next;
/**
* Constructs an uninitialized {@link Item}.
*/
Item() {
}
/**
* Constructs an uninitialized {@link Item} for constant pool element at
* given position.
*
* @param index
* index of the item to be constructed.
*/
Item(final int index) {
this.index = index;
}
/**
* Constructs a copy of the given item.
*
* @param index
* index of the item to be constructed.
* @param i
* the item that must be copied into the item to be constructed.
*/
Item(final int index, final Item i) {
this.index = index;
type = i.type;
intVal = i.intVal;
longVal = i.longVal;
strVal1 = i.strVal1;
strVal2 = i.strVal2;
strVal3 = i.strVal3;
hashCode = i.hashCode;
}
/**
* Sets this item to an integer item.
*
* @param intVal
* the value of this item.
*/
void set(final int intVal) {
this.type = ClassWriter.INT;
this.intVal = intVal;
this.hashCode = 0x7FFFFFFF & (type + intVal);
}
/**
* Sets this item to a long item.
*
* @param longVal
* the value of this item.
*/
void set(final long longVal) {
this.type = ClassWriter.LONG;
this.longVal = longVal;
this.hashCode = 0x7FFFFFFF & (type + (int) longVal);
}
/**
* Sets this item to a float item.
*
* @param floatVal
* the value of this item.
*/
void set(final float floatVal) {
this.type = ClassWriter.FLOAT;
this.intVal = Float.floatToRawIntBits(floatVal);
this.hashCode = 0x7FFFFFFF & (type + (int) floatVal);
}
/**
* Sets this item to a double item.
*
* @param doubleVal
* the value of this item.
*/
void set(final double doubleVal) {
this.type = ClassWriter.DOUBLE;
this.longVal = Double.doubleToRawLongBits(doubleVal);
this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal);
}
/**
* Sets this item to an item that do not hold a primitive value.
*
* @param type
* the type of this item.
* @param strVal1
* first part of the value of this item.
* @param strVal2
* second part of the value of this item.
* @param strVal3
* third part of the value of this item.
*/
@SuppressWarnings("fallthrough")
void set(final int type, final String strVal1, final String strVal2,
final String strVal3) {
this.type = type;
this.strVal1 = strVal1;
this.strVal2 = strVal2;
this.strVal3 = strVal3;
switch (type) {
case ClassWriter.CLASS:
this.intVal = 0; // intVal of a class must be zero, see visitInnerClass
case ClassWriter.UTF8:
case ClassWriter.STR:
case ClassWriter.MTYPE:
case ClassWriter.MODULE:
case ClassWriter.PACKAGE:
case ClassWriter.TYPE_NORMAL:
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
return;
case ClassWriter.NAME_TYPE: {
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
* strVal2.hashCode());
return;
}
// ClassWriter.FIELD:
// ClassWriter.METH:
// ClassWriter.IMETH:
// ClassWriter.HANDLE_BASE + 1..9
default:
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
* strVal2.hashCode() * strVal3.hashCode());
}
}
/**
* Sets the item to an InvokeDynamic item.
*
* @param name
* invokedynamic's name.
* @param desc
* invokedynamic's desc.
* @param bsmIndex
* zero based index into the class attribute BootrapMethods.
*/
void set(String name, String desc, int bsmIndex) {
this.type = ClassWriter.INDY;
this.longVal = bsmIndex;
this.strVal1 = name;
this.strVal2 = desc;
this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex
* strVal1.hashCode() * strVal2.hashCode());
}
/**
* Sets the item to a BootstrapMethod item.
*
* @param position
* position in byte in the class attribute BootrapMethods.
* @param hashCode
* hashcode of the item. This hashcode is processed from the
* hashcode of the bootstrap method and the hashcode of all
* bootstrap arguments.
*/
void set(int position, int hashCode) {
this.type = ClassWriter.BSM;
this.intVal = position;
this.hashCode = hashCode;
}
/**
* Indicates if the given item is equal to this one. <i>This method assumes
* that the two items have the same {@link #type}</i>.
*
* @param i
* the item to be compared to this one. Both items must have the
* same {@link #type}.
* @return <tt>true</tt> if the given item if equal to this one,
* <tt>false</tt> otherwise.
*/
boolean isEqualTo(final Item i) {
switch (type) {
case ClassWriter.UTF8:
case ClassWriter.STR:
case ClassWriter.CLASS:
case ClassWriter.MODULE:
case ClassWriter.PACKAGE:
case ClassWriter.MTYPE:
case ClassWriter.TYPE_NORMAL:
return i.strVal1.equals(strVal1);
case ClassWriter.TYPE_MERGED:
case ClassWriter.LONG:
case ClassWriter.DOUBLE:
return i.longVal == longVal;
case ClassWriter.INT:
case ClassWriter.FLOAT:
return i.intVal == intVal;
case ClassWriter.TYPE_UNINIT:
return i.intVal == intVal && i.strVal1.equals(strVal1);
case ClassWriter.NAME_TYPE:
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
case ClassWriter.INDY: {
return i.longVal == longVal && i.strVal1.equals(strVal1)
&& i.strVal2.equals(strVal2);
}
// case ClassWriter.FIELD:
// case ClassWriter.METH:
// case ClassWriter.IMETH:
// case ClassWriter.HANDLE_BASE + 1..9
default:
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2)
&& i.strVal3.equals(strVal3);
}
}
}

View File

@@ -0,0 +1,593 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* A label represents a position in the bytecode of a method. Labels are used
* for jump, goto, and switch instructions, and for try catch blocks. A label
* designates the <i>instruction</i> that is just after. Note however that there
* can be other elements between a label and the instruction it designates (such
* as other labels, stack map frames, line numbers, etc.).
*
* @author Eric Bruneton
*/
public class Label {
/**
* Indicates if this label is only used for debug attributes. Such a label
* is not the start of a basic block, the target of a jump instruction, or
* an exception handler. It can be safely ignored in control flow graph
* analysis algorithms (for optimization purposes).
*/
static final int DEBUG = 1;
/**
* Indicates if the position of this label is known.
*/
static final int RESOLVED = 2;
/**
* Indicates if this label has been updated, after instruction resizing.
*/
static final int RESIZED = 4;
/**
* Indicates if this basic block has been pushed in the basic block stack.
* See {@link MethodWriter#visitMaxs visitMaxs}.
*/
static final int PUSHED = 8;
/**
* Indicates if this label is the target of a jump instruction, or the start
* of an exception handler.
*/
static final int TARGET = 16;
/**
* Indicates if a stack map frame must be stored for this label.
*/
static final int STORE = 32;
/**
* Indicates if this label corresponds to a reachable basic block.
*/
static final int REACHABLE = 64;
/**
* Indicates if this basic block ends with a JSR instruction.
*/
static final int JSR = 128;
/**
* Indicates if this basic block ends with a RET instruction.
*/
static final int RET = 256;
/**
* Indicates if this basic block is the start of a subroutine.
*/
static final int SUBROUTINE = 512;
/**
* Indicates if this subroutine basic block has been visited by a
* visitSubroutine(null, ...) call.
*/
static final int VISITED = 1024;
/**
* Indicates if this subroutine basic block has been visited by a
* visitSubroutine(!null, ...) call.
*/
static final int VISITED2 = 2048;
/**
* Field used to associate user information to a label. Warning: this field
* is used by the ASM tree package. In order to use it with the ASM tree
* package you must override the
*
*/
public Object info;
/**
* Flags that indicate the status of this label.
*
* @see #DEBUG
* @see #RESOLVED
* @see #RESIZED
* @see #PUSHED
* @see #TARGET
* @see #STORE
* @see #REACHABLE
* @see #JSR
* @see #RET
*/
int status;
/**
* The line number corresponding to this label, if known. If there are
* several lines, each line is stored in a separate label, all linked via
* their next field (these links are created in ClassReader and removed just
* before visitLabel is called, so that this does not impact the rest of the
* code).
*/
int line;
/**
* The position of this label in the code, if known.
*/
int position;
/**
* Number of forward references to this label, times two.
*/
private int referenceCount;
/**
* Informations about forward references. Each forward reference is
* described by two consecutive integers in this array: the first one is the
* position of the first byte of the bytecode instruction that contains the
* forward reference, while the second is the position of the first byte of
* the forward reference itself. In fact the sign of the first integer
* indicates if this reference uses 2 or 4 bytes, and its absolute value
* gives the position of the bytecode instruction. This array is also used
* as a bitset to store the subroutines to which a basic block belongs. This
* information is needed in {@linked MethodWriter#visitMaxs}, after all
* forward references have been resolved. Hence the same array can be used
* for both purposes without problems.
*/
private int[] srcAndRefPositions;
// ------------------------------------------------------------------------
/*
* Fields for the control flow and data flow graph analysis algorithms (used
* to compute the maximum stack size or the stack map frames). A control
* flow graph contains one node per "basic block", and one edge per "jump"
* from one basic block to another. Each node (i.e., each basic block) is
* represented by the Label object that corresponds to the first instruction
* of this basic block. Each node also stores the list of its successors in
* the graph, as a linked list of Edge objects.
*
* The control flow analysis algorithms used to compute the maximum stack
* size or the stack map frames are similar and use two steps. The first
* step, during the visit of each instruction, builds information about the
* state of the local variables and the operand stack at the end of each
* basic block, called the "output frame", <i>relatively</i> to the frame
* state at the beginning of the basic block, which is called the "input
* frame", and which is <i>unknown</i> during this step. The second step, in
* {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes
* information about the input frame of each basic block, from the input
* state of the first basic block (known from the method signature), and by
* the using the previously computed relative output frames.
*
* The algorithm used to compute the maximum stack size only computes the
* relative output and absolute input stack heights, while the algorithm
* used to compute stack map frames computes relative output frames and
* absolute input frames.
*/
/**
* Start of the output stack relatively to the input stack. The exact
* semantics of this field depends on the algorithm that is used.
*
* When only the maximum stack size is computed, this field is the number of
* elements in the input stack.
*
* When the stack map frames are completely computed, this field is the
* offset of the first output stack element relatively to the top of the
* input stack. This offset is always negative or null. A null offset means
* that the output stack must be appended to the input stack. A -n offset
* means that the first n output stack elements must replace the top n input
* stack elements, and that the other elements must be appended to the input
* stack.
*/
int inputStackTop;
/**
* Maximum height reached by the output stack, relatively to the top of the
* input stack. This maximum is always positive or null.
*/
int outputStackMax;
/**
* Information about the input and output stack map frames of this basic
* block. This field is only used when {@link ClassWriter#COMPUTE_FRAMES}
* option is used.
*/
Frame frame;
/**
* The successor of this label, in the order they are visited. This linked
* list does not include labels used for debug info only. If
* {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it
* does not contain successive labels that denote the same bytecode position
* (in this case only the first label appears in this list).
*/
Label successor;
/**
* The successors of this node in the control flow graph. These successors
* are stored in a linked list of {@link Edge Edge} objects, linked to each
* other by their {@link Edge#next} field.
*/
Edge successors;
/**
* The next basic block in the basic block stack. This stack is used in the
* main loop of the fix point algorithm used in the second step of the
* control flow analysis algorithms. It is also used in
* {@link #visitSubroutine} to avoid using a recursive method, and in
* ClassReader to temporarily store multiple source lines for a label.
*
* @see MethodWriter#visitMaxs
*/
Label next;
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
/**
* Constructs a new label.
*/
public Label() {
}
// ------------------------------------------------------------------------
// Methods to compute offsets and to manage forward references
// ------------------------------------------------------------------------
/**
* Returns the offset corresponding to this label. This offset is computed
* from the start of the method's bytecode. <i>This method is intended for
* {@link Attribute} sub classes, and is normally not needed by class
* generators or adapters.</i>
*
* @return the offset corresponding to this label.
* @throws IllegalStateException
* if this label is not resolved yet.
*/
public int getOffset() {
if ((status & RESOLVED) == 0) {
throw new IllegalStateException(
"Label offset position has not been resolved yet");
}
return position;
}
/**
* Puts a reference to this label in the bytecode of a method. If the
* position of the label is known, the offset is computed and written
* directly. Otherwise, a null offset is written and a new forward reference
* is declared for this label.
*
* @param owner
* the code writer that calls this method.
* @param out
* the bytecode of the method.
* @param source
* the position of first byte of the bytecode instruction that
* contains this label.
* @param wideOffset
* <tt>true</tt> if the reference must be stored in 4 bytes, or
* <tt>false</tt> if it must be stored with 2 bytes.
* @throws IllegalArgumentException
* if this label has not been created by the given code writer.
*/
void put(final MethodWriter owner, final ByteVector out, final int source,
final boolean wideOffset) {
if ((status & RESOLVED) == 0) {
if (wideOffset) {
addReference(-1 - source, out.length);
out.putInt(-1);
} else {
addReference(source, out.length);
out.putShort(-1);
}
} else {
if (wideOffset) {
out.putInt(position - source);
} else {
out.putShort(position - source);
}
}
}
/**
* Adds a forward reference to this label. This method must be called only
* for a true forward reference, i.e. only if this label is not resolved
* yet. For backward references, the offset of the reference can be, and
* must be, computed and stored directly.
*
* @param sourcePosition
* the position of the referencing instruction. This position
* will be used to compute the offset of this forward reference.
* @param referencePosition
* the position where the offset for this forward reference must
* be stored.
*/
private void addReference(final int sourcePosition,
final int referencePosition) {
if (srcAndRefPositions == null) {
srcAndRefPositions = new int[6];
}
if (referenceCount >= srcAndRefPositions.length) {
int[] a = new int[srcAndRefPositions.length + 6];
System.arraycopy(srcAndRefPositions, 0, a, 0,
srcAndRefPositions.length);
srcAndRefPositions = a;
}
srcAndRefPositions[referenceCount++] = sourcePosition;
srcAndRefPositions[referenceCount++] = referencePosition;
}
/**
* Resolves all forward references to this label. This method must be called
* when this label is added to the bytecode of the method, i.e. when its
* position becomes known. This method fills in the blanks that where left
* in the bytecode by each forward reference previously added to this label.
*
* @param owner
* the code writer that calls this method.
* @param position
* the position of this label in the bytecode.
* @param data
* the bytecode of the method.
* @return <tt>true</tt> if a blank that was left for this label was too
* small to store the offset. In such a case the corresponding jump
* instruction is replaced with a pseudo instruction (using unused
* opcodes) using an unsigned two bytes offset. These pseudo
* instructions will be replaced with standard bytecode instructions
* with wider offsets (4 bytes instead of 2), in ClassReader.
* @throws IllegalArgumentException
* if this label has already been resolved, or if it has not
* been created by the given code writer.
*/
boolean resolve(final MethodWriter owner, final int position,
final byte[] data) {
boolean needUpdate = false;
this.status |= RESOLVED;
this.position = position;
int i = 0;
while (i < referenceCount) {
int source = srcAndRefPositions[i++];
int reference = srcAndRefPositions[i++];
int offset;
if (source >= 0) {
offset = position - source;
if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
/*
* changes the opcode of the jump instruction, in order to
* be able to find it later (see resizeInstructions in
* MethodWriter). These temporary opcodes are similar to
* jump instruction opcodes, except that the 2 bytes offset
* is unsigned (and can therefore represent values from 0 to
* 65535, which is sufficient since the size of a method is
* limited to 65535 bytes).
*/
int opcode = data[reference - 1] & 0xFF;
if (opcode <= Opcodes.JSR) {
// changes IFEQ ... JSR to opcodes 202 to 217
data[reference - 1] = (byte) (opcode + 49);
} else {
// changes IFNULL and IFNONNULL to opcodes 218 and 219
data[reference - 1] = (byte) (opcode + 20);
}
needUpdate = true;
}
data[reference++] = (byte) (offset >>> 8);
data[reference] = (byte) offset;
} else {
offset = position + source + 1;
data[reference++] = (byte) (offset >>> 24);
data[reference++] = (byte) (offset >>> 16);
data[reference++] = (byte) (offset >>> 8);
data[reference] = (byte) offset;
}
}
return needUpdate;
}
/**
* Returns the first label of the series to which this label belongs. For an
* isolated label or for the first label in a series of successive labels,
* this method returns the label itself. For other labels it returns the
* first label of the series.
*
* @return the first label of the series to which this label belongs.
*/
Label getFirst() {
return frame == null ? this : frame.owner;
}
// ------------------------------------------------------------------------
// Methods related to subroutines
// ------------------------------------------------------------------------
/**
* Returns true is this basic block belongs to the given subroutine.
*
* @param id
* a subroutine id.
* @return true is this basic block belongs to the given subroutine.
*/
boolean inSubroutine(final long id) {
if ((status & Label.VISITED) != 0) {
return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0;
}
return false;
}
/**
* Returns true if this basic block and the given one belong to a common
* subroutine.
*
* @param block
* another basic block.
* @return true if this basic block and the given one belong to a common
* subroutine.
*/
boolean inSameSubroutine(final Label block) {
if ((status & VISITED) == 0 || (block.status & VISITED) == 0) {
return false;
}
for (int i = 0; i < srcAndRefPositions.length; ++i) {
if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) {
return true;
}
}
return false;
}
/**
* Marks this basic block as belonging to the given subroutine.
*
* @param id
* a subroutine id.
* @param nbSubroutines
* the total number of subroutines in the method.
*/
void addToSubroutine(final long id, final int nbSubroutines) {
if ((status & VISITED) == 0) {
status |= VISITED;
srcAndRefPositions = new int[nbSubroutines / 32 + 1];
}
srcAndRefPositions[(int) (id >>> 32)] |= (int) id;
}
/**
* Finds the basic blocks that belong to a given subroutine, and marks these
* blocks as belonging to this subroutine. This method follows the control
* flow graph to find all the blocks that are reachable from the current
* block WITHOUT following any JSR target.
*
* @param JSR
* a JSR block that jumps to this subroutine. If this JSR is not
* null it is added to the successor of the RET blocks found in
* the subroutine.
* @param id
* the id of this subroutine.
* @param nbSubroutines
* the total number of subroutines in the method.
*/
void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) {
// user managed stack of labels, to avoid using a recursive method
// (recursivity can lead to stack overflow with very large methods)
Label stack = this;
while (stack != null) {
// removes a label l from the stack
Label l = stack;
stack = l.next;
l.next = null;
if (JSR != null) {
if ((l.status & VISITED2) != 0) {
continue;
}
l.status |= VISITED2;
// adds JSR to the successors of l, if it is a RET block
if ((l.status & RET) != 0) {
if (!l.inSameSubroutine(JSR)) {
Edge e = new Edge();
e.info = l.inputStackTop;
e.successor = JSR.successors.successor;
e.next = l.successors;
l.successors = e;
}
}
} else {
// if the l block already belongs to subroutine 'id', continue
if (l.inSubroutine(id)) {
continue;
}
// marks the l block as belonging to subroutine 'id'
l.addToSubroutine(id, nbSubroutines);
}
// pushes each successor of l on the stack, except JSR targets
Edge e = l.successors;
while (e != null) {
// if the l block is a JSR block, then 'l.successors.next' leads
// to the JSR target (see {@link #visitJumpInsn}) and must
// therefore not be followed
if ((l.status & Label.JSR) == 0 || e != l.successors.next) {
// pushes e.successor on the stack if it not already added
if (e.successor.next == null) {
e.successor.next = stack;
stack = e.successor;
}
}
e = e.next;
}
}
}
// ------------------------------------------------------------------------
// Overriden Object methods
// ------------------------------------------------------------------------
/**
* Returns a string representation of this label.
*
* @return a string representation of this label.
*/
@Override
public String toString() {
return "L" + System.identityHashCode(this);
}
}

View File

@@ -3,10 +3,9 @@
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.util;
package org.redkale.asm;
import java.util.*;
import jdk.internal.org.objectweb.asm.*;
/**
* MethodVisitor 的调试类
@@ -15,13 +14,13 @@ import jdk.internal.org.objectweb.asm.*;
*
* @author zhangjx
*/
public class AsmMethodVisitor {
public class MethodDebugVisitor {
private final MethodVisitor visitor;
private boolean debug = false;
public AsmMethodVisitor setDebug(boolean d) {
public MethodDebugVisitor setDebug(boolean d) {
debug = d;
return this;
}
@@ -33,7 +32,7 @@ public class AsmMethodVisitor {
System.out.println();
}
private final Map<Label, Integer> labels = new LinkedHashMap();
private final Map<Label, Integer> labels = new LinkedHashMap<>();
private static final String[] opcodes = new String[200]; //0 -18
@@ -55,7 +54,7 @@ public class AsmMethodVisitor {
}
}
public AsmMethodVisitor(MethodVisitor visitor) {
public MethodDebugVisitor(MethodVisitor visitor) {
//super(Opcodes.ASM5, visitor);
this.visitor = visitor;
}
@@ -173,7 +172,7 @@ public class AsmMethodVisitor {
if (debug) {
if (o instanceof CharSequence) {
System.out.println("mv.visitLdcInsn(\"" + o + "\");");
} else if (o instanceof jdk.internal.org.objectweb.asm.Type) {
} else if (o instanceof org.redkale.asm.Type) {
System.out.println("mv.visitLdcInsn(Type.getType(\"" + o + "\"));");
} else {
System.out.println("mv.visitLdcInsn(" + o + ");");

View File

@@ -0,0 +1,856 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* A visitor to visit a Java method. The methods of this class must be called in
* the following order: ( <tt>visitParameter</tt> )* [
* <tt>visitAnnotationDefault</tt> ] ( <tt>visitAnnotation</tt> |
* <tt>visitParameterAnnotation</tt> <tt>visitTypeAnnotation</tt> |
* <tt>visitAttribute</tt> )* [ <tt>visitCode</tt> ( <tt>visitFrame</tt> |
* <tt>visit<i>X</i>Insn</tt> | <tt>visitLabel</tt> |
* <tt>visitInsnAnnotation</tt> | <tt>visitTryCatchBlock</tt> |
* <tt>visitTryCatchAnnotation</tt> | <tt>visitLocalVariable</tt> |
* <tt>visitLocalVariableAnnotation</tt> | <tt>visitLineNumber</tt> )*
* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In addition, the
* <tt>visit<i>X</i>Insn</tt> and <tt>visitLabel</tt> methods must be called in
* the sequential order of the bytecode instructions of the visited code,
* <tt>visitInsnAnnotation</tt> must be called <i>after</i> the annotated
* instruction, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the
* labels passed as arguments have been visited,
* <tt>visitTryCatchBlockAnnotation</tt> must be called <i>after</i> the
* corresponding try catch block has been visited, and the
* <tt>visitLocalVariable</tt>, <tt>visitLocalVariableAnnotation</tt> and
* <tt>visitLineNumber</tt> methods must be called <i>after</i> the labels
* passed as arguments have been visited.
*
* @author Eric Bruneton
*/
public abstract class MethodVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
protected final int api;
/**
* The method visitor to which this visitor must delegate method calls. May
* be null.
*/
protected MethodVisitor mv;
/**
* Constructs a new {@link MethodVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
public MethodVisitor(final int api) {
this(api, null);
}
/**
* Constructs a new {@link MethodVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param mv
* the method visitor to which this visitor must delegate method
* calls. May be null.
*/
public MethodVisitor(final int api, final MethodVisitor mv) {
this.api = api;
this.mv = mv;
}
// -------------------------------------------------------------------------
// Parameters, annotations and non standard attributes
// -------------------------------------------------------------------------
/**
* Visits a parameter of this method.
*
* @param name
* parameter name or null if none is provided.
* @param access
* the parameter's access flags, only <tt>ACC_FINAL</tt>,
* <tt>ACC_SYNTHETIC</tt> or/and <tt>ACC_MANDATED</tt> are
* allowed (see {@link Opcodes}).
*/
public void visitParameter(String name, int access) {
if (mv != null) {
mv.visitParameter(name, access);
}
}
/**
* Visits the default value of this annotation interface method.
*
* @return a visitor to the visit the actual default value of this
* annotation interface method, or <tt>null</tt> if this visitor is
* not interested in visiting this default value. The 'name'
* parameters passed to the methods of this annotation visitor are
* ignored. Moreover, exacly one visit method must be called on this
* annotation visitor, followed by visitEnd.
*/
public AnnotationVisitor visitAnnotationDefault() {
if (mv != null) {
return mv.visitAnnotationDefault();
}
return null;
}
/**
* Visits an annotation of this method.
*
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (mv != null) {
return mv.visitAnnotation(desc, visible);
}
return null;
}
/**
* Visits an annotation on a type in the method signature.
*
* @param typeRef
* a reference to the annotated type. The sort of this type
* reference must be {@link TypeReference#METHOD_TYPE_PARAMETER
* METHOD_TYPE_PARAMETER},
* {@link TypeReference#METHOD_TYPE_PARAMETER_BOUND
* METHOD_TYPE_PARAMETER_BOUND},
* {@link TypeReference#METHOD_RETURN METHOD_RETURN},
* {@link TypeReference#METHOD_RECEIVER METHOD_RECEIVER},
* {@link TypeReference#METHOD_FORMAL_PARAMETER
* METHOD_FORMAL_PARAMETER} or {@link TypeReference#THROWS
* THROWS}. See {@link TypeReference}.
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
if (mv != null) {
return mv.visitTypeAnnotation(typeRef, typePath, desc, visible);
}
return null;
}
/**
* Visits an annotation of a parameter this method.
*
* @param parameter
* the parameter index.
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitParameterAnnotation(int parameter,
String desc, boolean visible) {
if (mv != null) {
return mv.visitParameterAnnotation(parameter, desc, visible);
}
return null;
}
/**
* Visits a non standard attribute of this method.
*
* @param attr
* an attribute.
*/
public void visitAttribute(Attribute attr) {
if (mv != null) {
mv.visitAttribute(attr);
}
}
/**
* Starts the visit of the method's code, if any (i.e. non abstract method).
*/
public void visitCode() {
if (mv != null) {
mv.visitCode();
}
}
/**
* Visits the current state of the local variables and operand stack
* elements. This method must(*) be called <i>just before</i> any
* instruction <b>i</b> that follows an unconditional branch instruction
* such as GOTO or THROW, that is the target of a jump instruction, or that
* starts an exception handler block. The visited types must describe the
* values of the local variables and of the operand stack elements <i>just
* before</i> <b>i</b> is executed.<br>
* <br>
* (*) this is mandatory only for classes whose version is greater than or
* equal to {@link Opcodes#V1_6 V1_6}. <br>
* <br>
* The frames of a method must be given either in expanded form, or in
* compressed form (all frames must use the same format, i.e. you must not
* mix expanded and compressed frames within a single method):
* <ul>
* <li>In expanded form, all frames must have the F_NEW type.</li>
* <li>In compressed form, frames are basically "deltas" from the state of
* the previous frame:
* <ul>
* <li>{@link Opcodes#F_SAME} representing frame with exactly the same
* locals as the previous frame and with the empty stack.</li>
* <li>{@link Opcodes#F_SAME1} representing frame with exactly the same
* locals as the previous frame and with single value on the stack (
* <code>nStack</code> is 1 and <code>stack[0]</code> contains value for the
* type of the stack item).</li>
* <li>{@link Opcodes#F_APPEND} representing frame with current locals are
* the same as the locals in the previous frame, except that additional
* locals are defined (<code>nLocal</code> is 1, 2 or 3 and
* <code>local</code> elements contains values representing added types).</li>
* <li>{@link Opcodes#F_CHOP} representing frame with current locals are the
* same as the locals in the previous frame, except that the last 1-3 locals
* are absent and with the empty stack (<code>nLocals</code> is 1, 2 or 3).</li>
* <li>{@link Opcodes#F_FULL} representing complete frame data.</li>
* </ul>
* </li>
* </ul>
* <br>
* In both cases the first frame, corresponding to the method's parameters
* and access flags, is implicit and must not be visited. Also, it is
* illegal to visit two or more frames for the same code location (i.e., at
* least one instruction must be visited between two calls to visitFrame).
*
* @param type
* the type of this stack map frame. Must be
* {@link Opcodes#F_NEW} for expanded frames, or
* {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND},
* {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
* {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for
* compressed frames.
* @param nLocal
* the number of local variables in the visited frame.
* @param local
* the local variable types in this frame. This array must not be
* modified. Primitive types are represented by
* {@link Opcodes#TOP}, {@link Opcodes#INTEGER},
* {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
* {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
* {@link Opcodes#UNINITIALIZED_THIS} (long and double are
* represented by a single element). Reference types are
* represented by String objects (representing internal names),
* and uninitialized types by Label objects (this label
* designates the NEW instruction that created this uninitialized
* value).
* @param nStack
* the number of operand stack elements in the visited frame.
* @param stack
* the operand stack types in this frame. This array must not be
* modified. Its content has the same format as the "local"
* array.
* @throws IllegalStateException
* if a frame is visited just after another one, without any
* instruction between the two (unless this frame is a
* Opcodes#F_SAME frame, in which case it is silently ignored).
*/
public void visitFrame(int type, int nLocal, Object[] local, int nStack,
Object[] stack) {
if (mv != null) {
mv.visitFrame(type, nLocal, local, nStack, stack);
}
}
// -------------------------------------------------------------------------
// Normal instructions
// -------------------------------------------------------------------------
/**
* Visits a zero operand instruction.
*
* @param opcode
* the opcode of the instruction to be visited. This opcode is
* either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1,
* ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1,
* FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD,
* LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
* IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE,
* SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1,
* DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB,
* IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM,
* FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR,
* IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D,
* L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S,
* LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
* DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER,
* or MONITOREXIT.
*/
public void visitInsn(int opcode) {
if (mv != null) {
mv.visitInsn(opcode);
}
}
/**
* Visits an instruction with a single int operand.
*
* @param opcode
* the opcode of the instruction to be visited. This opcode is
* either BIPUSH, SIPUSH or NEWARRAY.
* @param operand
* the operand of the instruction to be visited.<br>
* When opcode is BIPUSH, operand value should be between
* Byte.MIN_VALUE and Byte.MAX_VALUE.<br>
* When opcode is SIPUSH, operand value should be between
* Short.MIN_VALUE and Short.MAX_VALUE.<br>
* When opcode is NEWARRAY, operand value should be one of
* {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR},
* {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE},
* {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT},
* {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
*/
public void visitIntInsn(int opcode, int operand) {
if (mv != null) {
mv.visitIntInsn(opcode, operand);
}
}
/**
* Visits a local variable instruction. A local variable instruction is an
* instruction that loads or stores the value of a local variable.
*
* @param opcode
* the opcode of the local variable instruction to be visited.
* This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD,
* ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
* @param var
* the operand of the instruction to be visited. This operand is
* the index of a local variable.
*/
public void visitVarInsn(int opcode, int var) {
if (mv != null) {
mv.visitVarInsn(opcode, var);
}
}
/**
* Visits a type instruction. A type instruction is an instruction that
* takes the internal name of a class as parameter.
*
* @param opcode
* the opcode of the type instruction to be visited. This opcode
* is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
* @param type
* the operand of the instruction to be visited. This operand
* must be the internal name of an object or array class (see
* {@link Type#getInternalName() getInternalName}).
*/
public void visitTypeInsn(int opcode, String type) {
if (mv != null) {
mv.visitTypeInsn(opcode, type);
}
}
/**
* Visits a field instruction. A field instruction is an instruction that
* loads or stores the value of a field of an object.
*
* @param opcode
* the opcode of the type instruction to be visited. This opcode
* is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
* @param owner
* the internal name of the field's owner class (see
* {@link Type#getInternalName() getInternalName}).
* @param name
* the field's name.
* @param desc
* the field's descriptor (see {@link Type Type}).
*/
public void visitFieldInsn(int opcode, String owner, String name,
String desc) {
if (mv != null) {
mv.visitFieldInsn(opcode, owner, name, desc);
}
}
/**
* Visits a method instruction. A method instruction is an instruction that
* invokes a method.
*
* @param opcode
* the opcode of the type instruction to be visited. This opcode
* is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
* INVOKEINTERFACE.
* @param owner
* the internal name of the method's owner class (see
* {@link Type#getInternalName() getInternalName}).
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link Type Type}).
* @param itf
* if the method's owner class is an interface.
*/
public void visitMethodInsn(int opcode, String owner, String name,
String desc, boolean itf) {
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc, itf);
}
}
/**
* Visits an invokedynamic instruction.
*
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link Type Type}).
* @param bsm
* the bootstrap method.
* @param bsmArgs
* the bootstrap method constant arguments. Each argument must be
* an {@link Integer}, {@link Float}, {@link Long},
* {@link Double}, {@link String}, {@link Type} or {@link Handle}
* value. This method is allowed to modify the content of the
* array so a caller should expect that this array may change.
*/
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
Object... bsmArgs) {
if (mv != null) {
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
}
}
/**
* Visits a jump instruction. A jump instruction is an instruction that may
* jump to another instruction.
*
* @param opcode
* the opcode of the type instruction to be visited. This opcode
* is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
* IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
* IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
* @param label
* the operand of the instruction to be visited. This operand is
* a label that designates the instruction to which the jump
* instruction may jump.
*/
public void visitJumpInsn(int opcode, Label label) {
if (mv != null) {
mv.visitJumpInsn(opcode, label);
}
}
/**
* Visits a label. A label designates the instruction that will be visited
* just after it.
*
* @param label
* a {@link Label Label} object.
*/
public void visitLabel(Label label) {
if (mv != null) {
mv.visitLabel(label);
}
}
// -------------------------------------------------------------------------
// Special instructions
// -------------------------------------------------------------------------
/**
* Visits a LDC instruction. Note that new constant types may be added in
* future versions of the Java Virtual Machine. To easily detect new
* constant types, implementations of this method should check for
* unexpected constant types, like this:
*
* <pre>
* if (cst instanceof Integer) {
* // ...
* } else if (cst instanceof Float) {
* // ...
* } else if (cst instanceof Long) {
* // ...
* } else if (cst instanceof Double) {
* // ...
* } else if (cst instanceof String) {
* // ...
* } else if (cst instanceof Type) {
* int sort = ((Type) cst).getSort();
* if (sort == Type.OBJECT) {
* // ...
* } else if (sort == Type.ARRAY) {
* // ...
* } else if (sort == Type.METHOD) {
* // ...
* } else {
* // throw an exception
* }
* } else if (cst instanceof Handle) {
* // ...
* } else {
* // throw an exception
* }
* </pre>
*
* @param cst
* the constant to be loaded on the stack. This parameter must be
* a non null {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double}, a {@link String}, a {@link Type} of OBJECT or
* ARRAY sort for <tt>.class</tt> constants, for classes whose
* version is 49.0, a {@link Type} of METHOD sort or a
* {@link Handle} for MethodType and MethodHandle constants, for
* classes whose version is 51.0.
*/
public void visitLdcInsn(Object cst) {
if (mv != null) {
mv.visitLdcInsn(cst);
}
}
/**
* Visits an IINC instruction.
*
* @param var
* index of the local variable to be incremented.
* @param increment
* amount to increment the local variable by.
*/
public void visitIincInsn(int var, int increment) {
if (mv != null) {
mv.visitIincInsn(var, increment);
}
}
/**
* Visits a TABLESWITCH instruction.
*
* @param min
* the minimum key value.
* @param max
* the maximum key value.
* @param dflt
* beginning of the default handler block.
* @param labels
* beginnings of the handler blocks. <tt>labels[i]</tt> is the
* beginning of the handler block for the <tt>min + i</tt> key.
*/
public void visitTableSwitchInsn(int min, int max, Label dflt,
Label... labels) {
if (mv != null) {
mv.visitTableSwitchInsn(min, max, dflt, labels);
}
}
/**
* Visits a LOOKUPSWITCH instruction.
*
* @param dflt
* beginning of the default handler block.
* @param keys
* the values of the keys.
* @param labels
* beginnings of the handler blocks. <tt>labels[i]</tt> is the
* beginning of the handler block for the <tt>keys[i]</tt> key.
*/
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
if (mv != null) {
mv.visitLookupSwitchInsn(dflt, keys, labels);
}
}
/**
* Visits a MULTIANEWARRAY instruction.
*
* @param desc
* an array type descriptor (see {@link Type Type}).
* @param dims
* number of dimensions of the array to allocate.
*/
public void visitMultiANewArrayInsn(String desc, int dims) {
if (mv != null) {
mv.visitMultiANewArrayInsn(desc, dims);
}
}
/**
* Visits an annotation on an instruction. This method must be called just
* <i>after</i> the annotated instruction. It can be called several times
* for the same instruction.
*
* @param typeRef
* a reference to the annotated type. The sort of this type
* reference must be {@link TypeReference#INSTANCEOF INSTANCEOF},
* {@link TypeReference#NEW NEW},
* {@link TypeReference#CONSTRUCTOR_REFERENCE
* CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE
* METHOD_REFERENCE}, {@link TypeReference#CAST CAST},
* {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
* {@link TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT
* METHOD_INVOCATION_TYPE_ARGUMENT},
* {@link TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
* {@link TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT
* METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link TypeReference}.
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitInsnAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
if (mv != null) {
return mv.visitInsnAnnotation(typeRef, typePath, desc, visible);
}
return null;
}
// -------------------------------------------------------------------------
// Exceptions table entries, debug information, max stack and max locals
// -------------------------------------------------------------------------
/**
* Visits a try catch block.
*
* @param start
* beginning of the exception handler's scope (inclusive).
* @param end
* end of the exception handler's scope (exclusive).
* @param handler
* beginning of the exception handler's code.
* @param type
* internal name of the type of exceptions handled by the
* handler, or <tt>null</tt> to catch any exceptions (for
* "finally" blocks).
* @throws IllegalArgumentException
* if one of the labels has already been visited by this visitor
* (by the {@link #visitLabel visitLabel} method).
*/
public void visitTryCatchBlock(Label start, Label end, Label handler,
String type) {
if (mv != null) {
mv.visitTryCatchBlock(start, end, handler, type);
}
}
/**
* Visits an annotation on an exception handler type. This method must be
* called <i>after</i> the {@link #visitTryCatchBlock} for the annotated
* exception handler. It can be called several times for the same exception
* handler.
*
* @param typeRef
* a reference to the annotated type. The sort of this type
* reference must be {@link TypeReference#EXCEPTION_PARAMETER
* EXCEPTION_PARAMETER}. See {@link TypeReference}.
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
if (mv != null) {
return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible);
}
return null;
}
/**
* Visits a local variable declaration.
*
* @param name
* the name of a local variable.
* @param desc
* the type descriptor of this local variable.
* @param signature
* the type signature of this local variable. May be
* <tt>null</tt> if the local variable type does not use generic
* types.
* @param start
* the first instruction corresponding to the scope of this local
* variable (inclusive).
* @param end
* the last instruction corresponding to the scope of this local
* variable (exclusive).
* @param index
* the local variable's index.
* @throws IllegalArgumentException
* if one of the labels has not already been visited by this
* visitor (by the {@link #visitLabel visitLabel} method).
*/
public void visitLocalVariable(String name, String desc, String signature,
Label start, Label end, int index) {
if (mv != null) {
mv.visitLocalVariable(name, desc, signature, start, end, index);
}
}
/**
* Visits an annotation on a local variable type.
*
* @param typeRef
* a reference to the annotated type. The sort of this type
* reference must be {@link TypeReference#LOCAL_VARIABLE
* LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE
* RESOURCE_VARIABLE}. See {@link TypeReference}.
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param start
* the fist instructions corresponding to the continuous ranges
* that make the scope of this local variable (inclusive).
* @param end
* the last instructions corresponding to the continuous ranges
* that make the scope of this local variable (exclusive). This
* array must have the same size as the 'start' array.
* @param index
* the local variable's index in each range. This array must have
* the same size as the 'start' array.
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
TypePath typePath, Label[] start, Label[] end, int[] index,
String desc, boolean visible) {
if (mv != null) {
return mv.visitLocalVariableAnnotation(typeRef, typePath, start,
end, index, desc, visible);
}
return null;
}
/**
* Visits a line number declaration.
*
* @param line
* a line number. This number refers to the source file from
* which the class was compiled.
* @param start
* the first instruction corresponding to this line number.
* @throws IllegalArgumentException
* if <tt>start</tt> has not already been visited by this
* visitor (by the {@link #visitLabel visitLabel} method).
*/
public void visitLineNumber(int line, Label start) {
if (mv != null) {
mv.visitLineNumber(line, start);
}
}
/**
* Visits the maximum stack size and the maximum number of local variables
* of the method.
*
* @param maxStack
* maximum stack size of the method.
* @param maxLocals
* maximum number of local variables for the method.
*/
public void visitMaxs(int maxStack, int maxLocals) {
if (mv != null) {
mv.visitMaxs(maxStack, maxLocals);
}
}
/**
* Visits the end of the method. This method, which is the last one to be
* called, is used to inform the visitor that all the annotations and
* attributes of the method have been visited.
*/
public void visitEnd() {
if (mv != null) {
mv.visitEnd();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,219 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* A visitor to visit a Java module. The methods of this class must be called in
* the following order: <tt>visitMainClass</tt> | ( <tt>visitPackage</tt> |
* <tt>visitRequire</tt> | <tt>visitExport</tt> | <tt>visitOpen</tt> |
* <tt>visitUse</tt> | <tt>visitProvide</tt> )* <tt>visitEnd</tt>.
*
* The methods {@link #visitRequire(String, int, String)}, {@link #visitExport(String, int, String...)},
* {@link #visitOpen(String, int, String...)} and {@link #visitPackage(String)}
* take as parameter a package name or a module name. Unlike the other names which are internal names
* (names separated by slash), module and package names are qualified names (names separated by dot).
*
* @author Remi Forax
*/
public abstract class ModuleVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be {@link Opcodes#ASM6}.
*/
protected final int api;
/**
* The module visitor to which this visitor must delegate method calls. May
* be null.
*/
protected ModuleVisitor mv;
/**
* Constructs a new {@link ModuleVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
*/
public ModuleVisitor(final int api) {
this(api, null);
}
/**
* Constructs a new {@link ModuleVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
* @param mv
* the module visitor to which this visitor must delegate method
* calls. May be null.
*/
public ModuleVisitor(final int api, final ModuleVisitor mv) {
if (api != Opcodes.ASM6) {
throw new IllegalArgumentException();
}
this.api = api;
this.mv = mv;
}
/**
* Visit the main class of the current module.
*
* @param mainClass the internal name of the main class of the current module.
*/
public void visitMainClass(String mainClass) {
if (mv != null) {
mv.visitMainClass(mainClass);
}
}
/**
* Visit a package of the current module.
*
* @param packaze the qualified name of a package.
*/
public void visitPackage(String packaze) {
if (mv != null) {
mv.visitPackage(packaze);
}
}
/**
* Visits a dependence of the current module.
*
* @param module the qualified name of the dependence.
* @param access the access flag of the dependence among
* ACC_TRANSITIVE, ACC_STATIC_PHASE, ACC_SYNTHETIC
* and ACC_MANDATED.
* @param version the module version at compile time or null.
*/
public void visitRequire(String module, int access, String version) {
if (mv != null) {
mv.visitRequire(module, access, version);
}
}
/**
* Visit an exported package of the current module.
*
* @param packaze the qualified name of the exported package.
* @param access the access flag of the exported package,
* valid values are among {@code ACC_SYNTHETIC} and
* {@code ACC_MANDATED}.
* @param modules the qualified names of the modules that can access to
* the public classes of the exported package or
* <tt>null</tt>.
*/
public void visitExport(String packaze, int access, String... modules) {
if (mv != null) {
mv.visitExport(packaze, access, modules);
}
}
/**
* Visit an open package of the current module.
*
* @param packaze the qualified name of the opened package.
* @param access the access flag of the opened package,
* valid values are among {@code ACC_SYNTHETIC} and
* {@code ACC_MANDATED}.
* @param modules the qualified names of the modules that can use deep
* reflection to the classes of the open package or
* <tt>null</tt>.
*/
public void visitOpen(String packaze, int access, String... modules) {
if (mv != null) {
mv.visitOpen(packaze, access, modules);
}
}
/**
* Visit a service used by the current module.
* The name must be the internal name of an interface or a class.
*
* @param service the internal name of the service.
*/
public void visitUse(String service) {
if (mv != null) {
mv.visitUse(service);
}
}
/**
* Visit an implementation of a service.
*
* @param service the internal name of the service
* @param providers the internal names of the implementations
* of the service (there is at least one provider).
*/
public void visitProvide(String service, String... providers) {
if (mv != null) {
mv.visitProvide(service, providers);
}
}
/**
* Visits the end of the module. This method, which is the last one to be
* called, is used to inform the visitor that everything have been visited.
*/
public void visitEnd() {
if (mv != null) {
mv.visitEnd();
}
}
}

View File

@@ -0,0 +1,322 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* @author Remi Forax
*/
final class ModuleWriter extends ModuleVisitor {
/**
* The class writer to which this Module attribute must be added.
*/
private final ClassWriter cw;
/**
* size in byte of the Module attribute.
*/
int size;
/**
* Number of attributes associated with the current module
* (Version, ConcealPackages, etc)
*/
int attributeCount;
/**
* Size in bytes of the attributes associated with the current module
*/
int attributesSize;
/**
* module name index in the constant pool
*/
private final int name;
/**
* module access flags
*/
private final int access;
/**
* module version index in the constant pool or 0
*/
private final int version;
/**
* module main class index in the constant pool or 0
*/
private int mainClass;
/**
* number of packages
*/
private int packageCount;
/**
* The packages in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in packageCount
*/
private ByteVector packages;
/**
* number of requires items
*/
private int requireCount;
/**
* The requires items in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in requireCount
*/
private ByteVector requires;
/**
* number of exports items
*/
private int exportCount;
/**
* The exports items in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in exportCount
*/
private ByteVector exports;
/**
* number of opens items
*/
private int openCount;
/**
* The opens items in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in openCount
*/
private ByteVector opens;
/**
* number of uses items
*/
private int useCount;
/**
* The uses items in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in useCount
*/
private ByteVector uses;
/**
* number of provides items
*/
private int provideCount;
/**
* The uses provides in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in provideCount
*/
private ByteVector provides;
ModuleWriter(final ClassWriter cw, final int name,
final int access, final int version) {
super(Opcodes.ASM6);
this.cw = cw;
this.size = 16; // name + access + version + 5 counts
this.name = name;
this.access = access;
this.version = version;
}
@Override
public void visitMainClass(String mainClass) {
if (this.mainClass == 0) { // protect against several calls to visitMainClass
cw.newUTF8("ModuleMainClass");
attributeCount++;
attributesSize += 8;
}
this.mainClass = cw.newClass(mainClass);
}
@Override
public void visitPackage(String packaze) {
if (packages == null) {
// protect against several calls to visitPackage
cw.newUTF8("ModulePackages");
packages = new ByteVector();
attributeCount++;
attributesSize += 8;
}
packages.putShort(cw.newPackage(packaze));
packageCount++;
attributesSize += 2;
}
@Override
public void visitRequire(String module, int access, String version) {
if (requires == null) {
requires = new ByteVector();
}
requires.putShort(cw.newModule(module))
.putShort(access)
.putShort(version == null? 0: cw.newUTF8(version));
requireCount++;
size += 6;
}
@Override
public void visitExport(String packaze, int access, String... modules) {
if (exports == null) {
exports = new ByteVector();
}
exports.putShort(cw.newPackage(packaze)).putShort(access);
if (modules == null) {
exports.putShort(0);
size += 6;
} else {
exports.putShort(modules.length);
for(String module: modules) {
exports.putShort(cw.newModule(module));
}
size += 6 + 2 * modules.length;
}
exportCount++;
}
@Override
public void visitOpen(String packaze, int access, String... modules) {
if (opens == null) {
opens = new ByteVector();
}
opens.putShort(cw.newPackage(packaze)).putShort(access);
if (modules == null) {
opens.putShort(0);
size += 6;
} else {
opens.putShort(modules.length);
for(String module: modules) {
opens.putShort(cw.newModule(module));
}
size += 6 + 2 * modules.length;
}
openCount++;
}
@Override
public void visitUse(String service) {
if (uses == null) {
uses = new ByteVector();
}
uses.putShort(cw.newClass(service));
useCount++;
size += 2;
}
@Override
public void visitProvide(String service, String... providers) {
if (provides == null) {
provides = new ByteVector();
}
provides.putShort(cw.newClass(service));
provides.putShort(providers.length);
for(String provider: providers) {
provides.putShort(cw.newClass(provider));
}
provideCount++;
size += 4 + 2 * providers.length;
}
@Override
public void visitEnd() {
// empty
}
void putAttributes(ByteVector out) {
if (mainClass != 0) {
out.putShort(cw.newUTF8("ModuleMainClass")).putInt(2).putShort(mainClass);
}
if (packages != null) {
out.putShort(cw.newUTF8("ModulePackages"))
.putInt(2 + 2 * packageCount)
.putShort(packageCount)
.putByteArray(packages.data, 0, packages.length);
}
}
void put(ByteVector out) {
out.putInt(size);
out.putShort(name).putShort(access).putShort(version);
out.putShort(requireCount);
if (requires != null) {
out.putByteArray(requires.data, 0, requires.length);
}
out.putShort(exportCount);
if (exports != null) {
out.putByteArray(exports.data, 0, exports.length);
}
out.putShort(openCount);
if (opens != null) {
out.putByteArray(opens.data, 0, opens.length);
}
out.putShort(useCount);
if (uses != null) {
out.putByteArray(uses.data, 0, uses.length);
}
out.putShort(provideCount);
if (provides != null) {
out.putByteArray(provides.data, 0, provides.length);
}
}
}

View File

@@ -0,0 +1,398 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* Defines the JVM opcodes, access flags and array type codes. This interface
* does not define all the JVM opcodes because some opcodes are automatically
* handled. For example, the xLOAD and xSTORE opcodes are automatically replaced
* by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n
* opcodes are therefore not defined in this interface. Likewise for LDC,
* automatically replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and
* JSR_W.
*
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
public interface Opcodes {
// ASM API versions
int ASM4 = 4 << 16 | 0 << 8 | 0;
int ASM5 = 5 << 16 | 0 << 8 | 0;
int ASM6 = 6 << 16 | 0 << 8 | 0;
// versions
int V1_5 = 0 << 16 | 49;
int V1_6 = 0 << 16 | 50;
int V1_7 = 0 << 16 | 51;
int V1_8 = 0 << 16 | 52;
int V9 = 0 << 16 | 53;
int V10 = 0 << 16 | 54;
// access flags
int ACC_PUBLIC = 0x0001; // class, field, method
int ACC_PRIVATE = 0x0002; // class, field, method
int ACC_PROTECTED = 0x0004; // class, field, method
int ACC_STATIC = 0x0008; // field, method
int ACC_FINAL = 0x0010; // class, field, method, parameter
int ACC_SUPER = 0x0020; // class
int ACC_SYNCHRONIZED = 0x0020; // method
int ACC_OPEN = 0x0020; // module
int ACC_TRANSITIVE = 0x0020; // module requires
int ACC_VOLATILE = 0x0040; // field
int ACC_BRIDGE = 0x0040; // method
int ACC_STATIC_PHASE = 0x0040; // module requires
int ACC_VARARGS = 0x0080; // method
int ACC_TRANSIENT = 0x0080; // field
int ACC_NATIVE = 0x0100; // method
int ACC_INTERFACE = 0x0200; // class
int ACC_ABSTRACT = 0x0400; // class, method
int ACC_STRICT = 0x0800; // method
int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
int ACC_ANNOTATION = 0x2000; // class
int ACC_ENUM = 0x4000; // class(?) field inner
int ACC_MANDATED = 0x8000; // parameter, module, module *
int ACC_MODULE = 0x8000; // class
// ASM specific pseudo access flags
int ACC_DEPRECATED = 0x20000; // class, field, method
// types for NEWARRAY
int T_BOOLEAN = 4;
int T_CHAR = 5;
int T_FLOAT = 6;
int T_DOUBLE = 7;
int T_BYTE = 8;
int T_SHORT = 9;
int T_INT = 10;
int T_LONG = 11;
// tags for Handle
int H_GETFIELD = 1;
int H_GETSTATIC = 2;
int H_PUTFIELD = 3;
int H_PUTSTATIC = 4;
int H_INVOKEVIRTUAL = 5;
int H_INVOKESTATIC = 6;
int H_INVOKESPECIAL = 7;
int H_NEWINVOKESPECIAL = 8;
int H_INVOKEINTERFACE = 9;
// stack map frame types
/**
* Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}.
*/
int F_NEW = -1;
/**
* Represents a compressed frame with complete frame data.
*/
int F_FULL = 0;
/**
* Represents a compressed frame where locals are the same as the locals in
* the previous frame, except that additional 1-3 locals are defined, and
* with an empty stack.
*/
int F_APPEND = 1;
/**
* Represents a compressed frame where locals are the same as the locals in
* the previous frame, except that the last 1-3 locals are absent and with
* an empty stack.
*/
int F_CHOP = 2;
/**
* Represents a compressed frame with exactly the same locals as the
* previous frame and with an empty stack.
*/
int F_SAME = 3;
/**
* Represents a compressed frame with exactly the same locals as the
* previous frame and with a single value on the stack.
*/
int F_SAME1 = 4;
// Do not try to change the following code to use auto-boxing,
// these values are compared by reference and not by value
// The constructor of Integer was deprecated in 9
// but we are stuck with it by backward compatibility
@SuppressWarnings("deprecation") Integer TOP = new Integer(0);
@SuppressWarnings("deprecation") Integer INTEGER = new Integer(1);
@SuppressWarnings("deprecation") Integer FLOAT = new Integer(2);
@SuppressWarnings("deprecation") Integer DOUBLE = new Integer(3);
@SuppressWarnings("deprecation") Integer LONG = new Integer(4);
@SuppressWarnings("deprecation") Integer NULL = new Integer(5);
@SuppressWarnings("deprecation") Integer UNINITIALIZED_THIS = new Integer(6);
// opcodes // visit method (- = idem)
int NOP = 0; // visitInsn
int ACONST_NULL = 1; // -
int ICONST_M1 = 2; // -
int ICONST_0 = 3; // -
int ICONST_1 = 4; // -
int ICONST_2 = 5; // -
int ICONST_3 = 6; // -
int ICONST_4 = 7; // -
int ICONST_5 = 8; // -
int LCONST_0 = 9; // -
int LCONST_1 = 10; // -
int FCONST_0 = 11; // -
int FCONST_1 = 12; // -
int FCONST_2 = 13; // -
int DCONST_0 = 14; // -
int DCONST_1 = 15; // -
int BIPUSH = 16; // visitIntInsn
int SIPUSH = 17; // -
int LDC = 18; // visitLdcInsn
// int LDC_W = 19; // -
// int LDC2_W = 20; // -
int ILOAD = 21; // visitVarInsn
int LLOAD = 22; // -
int FLOAD = 23; // -
int DLOAD = 24; // -
int ALOAD = 25; // -
// int ILOAD_0 = 26; // -
// int ILOAD_1 = 27; // -
// int ILOAD_2 = 28; // -
// int ILOAD_3 = 29; // -
// int LLOAD_0 = 30; // -
// int LLOAD_1 = 31; // -
// int LLOAD_2 = 32; // -
// int LLOAD_3 = 33; // -
// int FLOAD_0 = 34; // -
// int FLOAD_1 = 35; // -
// int FLOAD_2 = 36; // -
// int FLOAD_3 = 37; // -
// int DLOAD_0 = 38; // -
// int DLOAD_1 = 39; // -
// int DLOAD_2 = 40; // -
// int DLOAD_3 = 41; // -
// int ALOAD_0 = 42; // -
// int ALOAD_1 = 43; // -
// int ALOAD_2 = 44; // -
// int ALOAD_3 = 45; // -
int IALOAD = 46; // visitInsn
int LALOAD = 47; // -
int FALOAD = 48; // -
int DALOAD = 49; // -
int AALOAD = 50; // -
int BALOAD = 51; // -
int CALOAD = 52; // -
int SALOAD = 53; // -
int ISTORE = 54; // visitVarInsn
int LSTORE = 55; // -
int FSTORE = 56; // -
int DSTORE = 57; // -
int ASTORE = 58; // -
// int ISTORE_0 = 59; // -
// int ISTORE_1 = 60; // -
// int ISTORE_2 = 61; // -
// int ISTORE_3 = 62; // -
// int LSTORE_0 = 63; // -
// int LSTORE_1 = 64; // -
// int LSTORE_2 = 65; // -
// int LSTORE_3 = 66; // -
// int FSTORE_0 = 67; // -
// int FSTORE_1 = 68; // -
// int FSTORE_2 = 69; // -
// int FSTORE_3 = 70; // -
// int DSTORE_0 = 71; // -
// int DSTORE_1 = 72; // -
// int DSTORE_2 = 73; // -
// int DSTORE_3 = 74; // -
// int ASTORE_0 = 75; // -
// int ASTORE_1 = 76; // -
// int ASTORE_2 = 77; // -
// int ASTORE_3 = 78; // -
int IASTORE = 79; // visitInsn
int LASTORE = 80; // -
int FASTORE = 81; // -
int DASTORE = 82; // -
int AASTORE = 83; // -
int BASTORE = 84; // -
int CASTORE = 85; // -
int SASTORE = 86; // -
int POP = 87; // -
int POP2 = 88; // -
int DUP = 89; // -
int DUP_X1 = 90; // -
int DUP_X2 = 91; // -
int DUP2 = 92; // -
int DUP2_X1 = 93; // -
int DUP2_X2 = 94; // -
int SWAP = 95; // -
int IADD = 96; // -
int LADD = 97; // -
int FADD = 98; // -
int DADD = 99; // -
int ISUB = 100; // -
int LSUB = 101; // -
int FSUB = 102; // -
int DSUB = 103; // -
int IMUL = 104; // -
int LMUL = 105; // -
int FMUL = 106; // -
int DMUL = 107; // -
int IDIV = 108; // -
int LDIV = 109; // -
int FDIV = 110; // -
int DDIV = 111; // -
int IREM = 112; // -
int LREM = 113; // -
int FREM = 114; // -
int DREM = 115; // -
int INEG = 116; // -
int LNEG = 117; // -
int FNEG = 118; // -
int DNEG = 119; // -
int ISHL = 120; // -
int LSHL = 121; // -
int ISHR = 122; // -
int LSHR = 123; // -
int IUSHR = 124; // -
int LUSHR = 125; // -
int IAND = 126; // -
int LAND = 127; // -
int IOR = 128; // -
int LOR = 129; // -
int IXOR = 130; // -
int LXOR = 131; // -
int IINC = 132; // visitIincInsn
int I2L = 133; // visitInsn
int I2F = 134; // -
int I2D = 135; // -
int L2I = 136; // -
int L2F = 137; // -
int L2D = 138; // -
int F2I = 139; // -
int F2L = 140; // -
int F2D = 141; // -
int D2I = 142; // -
int D2L = 143; // -
int D2F = 144; // -
int I2B = 145; // -
int I2C = 146; // -
int I2S = 147; // -
int LCMP = 148; // -
int FCMPL = 149; // -
int FCMPG = 150; // -
int DCMPL = 151; // -
int DCMPG = 152; // -
int IFEQ = 153; // visitJumpInsn
int IFNE = 154; // -
int IFLT = 155; // -
int IFGE = 156; // -
int IFGT = 157; // -
int IFLE = 158; // -
int IF_ICMPEQ = 159; // -
int IF_ICMPNE = 160; // -
int IF_ICMPLT = 161; // -
int IF_ICMPGE = 162; // -
int IF_ICMPGT = 163; // -
int IF_ICMPLE = 164; // -
int IF_ACMPEQ = 165; // -
int IF_ACMPNE = 166; // -
int GOTO = 167; // -
int JSR = 168; // -
int RET = 169; // visitVarInsn
int TABLESWITCH = 170; // visiTableSwitchInsn
int LOOKUPSWITCH = 171; // visitLookupSwitch
int IRETURN = 172; // visitInsn
int LRETURN = 173; // -
int FRETURN = 174; // -
int DRETURN = 175; // -
int ARETURN = 176; // -
int RETURN = 177; // -
int GETSTATIC = 178; // visitFieldInsn
int PUTSTATIC = 179; // -
int GETFIELD = 180; // -
int PUTFIELD = 181; // -
int INVOKEVIRTUAL = 182; // visitMethodInsn
int INVOKESPECIAL = 183; // -
int INVOKESTATIC = 184; // -
int INVOKEINTERFACE = 185; // -
int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn
int NEW = 187; // visitTypeInsn
int NEWARRAY = 188; // visitIntInsn
int ANEWARRAY = 189; // visitTypeInsn
int ARRAYLENGTH = 190; // visitInsn
int ATHROW = 191; // -
int CHECKCAST = 192; // visitTypeInsn
int INSTANCEOF = 193; // -
int MONITORENTER = 194; // visitInsn
int MONITOREXIT = 195; // -
// int WIDE = 196; // NOT VISITED
int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
int IFNULL = 198; // visitJumpInsn
int IFNONNULL = 199; // -
// int GOTO_W = 200; // -
// int JSR_W = 201; // -
}

View File

@@ -0,0 +1,934 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* A Java field or method type. This class can be used to make it easier to
* manipulate type and method descriptors.
*
* @author Eric Bruneton
* @author Chris Nokleberg
*/
public class Type {
/**
* The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
*/
public static final int VOID = 0;
/**
* The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
*/
public static final int BOOLEAN = 1;
/**
* The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
*/
public static final int CHAR = 2;
/**
* The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
*/
public static final int BYTE = 3;
/**
* The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
*/
public static final int SHORT = 4;
/**
* The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
*/
public static final int INT = 5;
/**
* The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
*/
public static final int FLOAT = 6;
/**
* The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
*/
public static final int LONG = 7;
/**
* The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
*/
public static final int DOUBLE = 8;
/**
* The sort of array reference types. See {@link #getSort getSort}.
*/
public static final int ARRAY = 9;
/**
* The sort of object reference types. See {@link #getSort getSort}.
*/
public static final int OBJECT = 10;
/**
* The sort of method types. See {@link #getSort getSort}.
*/
public static final int METHOD = 11;
/**
* The <tt>void</tt> type.
*/
public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24)
| (5 << 16) | (0 << 8) | 0, 1);
/**
* The <tt>boolean</tt> type.
*/
public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24)
| (0 << 16) | (5 << 8) | 1, 1);
/**
* The <tt>char</tt> type.
*/
public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24)
| (0 << 16) | (6 << 8) | 1, 1);
/**
* The <tt>byte</tt> type.
*/
public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24)
| (0 << 16) | (5 << 8) | 1, 1);
/**
* The <tt>short</tt> type.
*/
public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24)
| (0 << 16) | (7 << 8) | 1, 1);
/**
* The <tt>int</tt> type.
*/
public static final Type INT_TYPE = new Type(INT, null, ('I' << 24)
| (0 << 16) | (0 << 8) | 1, 1);
/**
* The <tt>float</tt> type.
*/
public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24)
| (2 << 16) | (2 << 8) | 1, 1);
/**
* The <tt>long</tt> type.
*/
public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24)
| (1 << 16) | (1 << 8) | 2, 1);
/**
* The <tt>double</tt> type.
*/
public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24)
| (3 << 16) | (3 << 8) | 2, 1);
// ------------------------------------------------------------------------
// Fields
// ------------------------------------------------------------------------
/**
* The sort of this Java type.
*/
private final int sort;
/**
* A buffer containing the internal name of this Java type. This field is
* only used for reference types.
*/
private final char[] buf;
/**
* The offset of the internal name of this Java type in {@link #buf buf} or,
* for primitive types, the size, descriptor and getOpcode offsets for this
* type (byte 0 contains the size, byte 1 the descriptor, byte 2 the offset
* for IALOAD or IASTORE, byte 3 the offset for all other instructions).
*/
private final int off;
/**
* The length of the internal name of this Java type.
*/
private final int len;
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------
/**
* Constructs a reference type.
*
* @param sort
* the sort of the reference type to be constructed.
* @param buf
* a buffer containing the descriptor of the previous type.
* @param off
* the offset of this descriptor in the previous buffer.
* @param len
* the length of this descriptor.
*/
private Type(final int sort, final char[] buf, final int off, final int len) {
this.sort = sort;
this.buf = buf;
this.off = off;
this.len = len;
}
/**
* Returns the Java type corresponding to the given type descriptor.
*
* @param typeDescriptor
* a field or method type descriptor.
* @return the Java type corresponding to the given type descriptor.
*/
public static Type getType(final String typeDescriptor) {
return getType(typeDescriptor.toCharArray(), 0);
}
/**
* Returns the Java type corresponding to the given internal name.
*
* @param internalName
* an internal name.
* @return the Java type corresponding to the given internal name.
*/
public static Type getObjectType(final String internalName) {
char[] buf = internalName.toCharArray();
return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length);
}
/**
* Returns the Java type corresponding to the given method descriptor.
* Equivalent to <code>Type.getType(methodDescriptor)</code>.
*
* @param methodDescriptor
* a method descriptor.
* @return the Java type corresponding to the given method descriptor.
*/
public static Type getMethodType(final String methodDescriptor) {
return getType(methodDescriptor.toCharArray(), 0);
}
/**
* Returns the Java method type corresponding to the given argument and
* return types.
*
* @param returnType
* the return type of the method.
* @param argumentTypes
* the argument types of the method.
* @return the Java type corresponding to the given argument and return
* types.
*/
public static Type getMethodType(final Type returnType,
final Type... argumentTypes) {
return getType(getMethodDescriptor(returnType, argumentTypes));
}
/**
* Returns the Java type corresponding to the given class.
*
* @param c
* a class.
* @return the Java type corresponding to the given class.
*/
public static Type getType(final Class<?> c) {
if (c.isPrimitive()) {
if (c == Integer.TYPE) {
return INT_TYPE;
} else if (c == Void.TYPE) {
return VOID_TYPE;
} else if (c == Boolean.TYPE) {
return BOOLEAN_TYPE;
} else if (c == Byte.TYPE) {
return BYTE_TYPE;
} else if (c == Character.TYPE) {
return CHAR_TYPE;
} else if (c == Short.TYPE) {
return SHORT_TYPE;
} else if (c == Double.TYPE) {
return DOUBLE_TYPE;
} else if (c == Float.TYPE) {
return FLOAT_TYPE;
} else /* if (c == Long.TYPE) */{
return LONG_TYPE;
}
} else {
return getType(getDescriptor(c));
}
}
/**
* Returns the Java method type corresponding to the given constructor.
*
* @param c
* a {@link Constructor Constructor} object.
* @return the Java method type corresponding to the given constructor.
*/
public static Type getType(final Constructor<?> c) {
return getType(getConstructorDescriptor(c));
}
/**
* Returns the Java method type corresponding to the given method.
*
* @param m
* a {@link Method Method} object.
* @return the Java method type corresponding to the given method.
*/
public static Type getType(final Method m) {
return getType(getMethodDescriptor(m));
}
/**
* Returns the Java types corresponding to the argument types of the given
* method descriptor.
*
* @param methodDescriptor
* a method descriptor.
* @return the Java types corresponding to the argument types of the given
* method descriptor.
*/
public static Type[] getArgumentTypes(final String methodDescriptor) {
char[] buf = methodDescriptor.toCharArray();
int off = 1;
int size = 0;
while (true) {
char car = buf[off++];
if (car == ')') {
break;
} else if (car == 'L') {
while (buf[off++] != ';') {
}
++size;
} else if (car != '[') {
++size;
}
}
Type[] args = new Type[size];
off = 1;
size = 0;
while (buf[off] != ')') {
args[size] = getType(buf, off);
off += args[size].len + (args[size].sort == OBJECT ? 2 : 0);
size += 1;
}
return args;
}
/**
* Returns the Java types corresponding to the argument types of the given
* method.
*
* @param method
* a method.
* @return the Java types corresponding to the argument types of the given
* method.
*/
public static Type[] getArgumentTypes(final Method method) {
Class<?>[] classes = method.getParameterTypes();
Type[] types = new Type[classes.length];
for (int i = classes.length - 1; i >= 0; --i) {
types[i] = getType(classes[i]);
}
return types;
}
/**
* Returns the Java type corresponding to the return type of the given
* method descriptor.
*
* @param methodDescriptor
* a method descriptor.
* @return the Java type corresponding to the return type of the given
* method descriptor.
*/
public static Type getReturnType(final String methodDescriptor) {
char[] buf = methodDescriptor.toCharArray();
int off = 1;
while (true) {
char car = buf[off++];
if (car == ')') {
return getType(buf, off);
} else if (car == 'L') {
while (buf[off++] != ';') {
}
}
}
}
/**
* Returns the Java type corresponding to the return type of the given
* method.
*
* @param method
* a method.
* @return the Java type corresponding to the return type of the given
* method.
*/
public static Type getReturnType(final Method method) {
return getType(method.getReturnType());
}
/**
* Computes the size of the arguments and of the return value of a method.
*
* @param desc
* the descriptor of a method.
* @return the size of the arguments of the method (plus one for the
* implicit this argument), argSize, and the size of its return
* value, retSize, packed into a single int i =
* <tt>(argSize &lt;&lt; 2) | retSize</tt> (argSize is therefore equal to
* <tt>i &gt;&gt; 2</tt>, and retSize to <tt>i &amp; 0x03</tt>).
*/
public static int getArgumentsAndReturnSizes(final String desc) {
int n = 1;
int c = 1;
while (true) {
char car = desc.charAt(c++);
if (car == ')') {
car = desc.charAt(c);
return n << 2
| (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
} else if (car == 'L') {
while (desc.charAt(c++) != ';') {
}
n += 1;
} else if (car == '[') {
while ((car = desc.charAt(c)) == '[') {
++c;
}
if (car == 'D' || car == 'J') {
n -= 1;
}
} else if (car == 'D' || car == 'J') {
n += 2;
} else {
n += 1;
}
}
}
/**
* Returns the Java type corresponding to the given type descriptor. For
* method descriptors, buf is supposed to contain nothing more than the
* descriptor itself.
*
* @param buf
* a buffer containing a type descriptor.
* @param off
* the offset of this descriptor in the previous buffer.
* @return the Java type corresponding to the given type descriptor.
*/
private static Type getType(final char[] buf, final int off) {
int len;
switch (buf[off]) {
case 'V':
return VOID_TYPE;
case 'Z':
return BOOLEAN_TYPE;
case 'C':
return CHAR_TYPE;
case 'B':
return BYTE_TYPE;
case 'S':
return SHORT_TYPE;
case 'I':
return INT_TYPE;
case 'F':
return FLOAT_TYPE;
case 'J':
return LONG_TYPE;
case 'D':
return DOUBLE_TYPE;
case '[':
len = 1;
while (buf[off + len] == '[') {
++len;
}
if (buf[off + len] == 'L') {
++len;
while (buf[off + len] != ';') {
++len;
}
}
return new Type(ARRAY, buf, off, len + 1);
case 'L':
len = 1;
while (buf[off + len] != ';') {
++len;
}
return new Type(OBJECT, buf, off + 1, len - 1);
// case '(':
default:
return new Type(METHOD, buf, off, buf.length - off);
}
}
// ------------------------------------------------------------------------
// Accessors
// ------------------------------------------------------------------------
/**
* Returns the sort of this Java type.
*
* @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR},
* {@link #BYTE BYTE}, {@link #SHORT SHORT}, {@link #INT INT},
* {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE},
* {@link #ARRAY ARRAY}, {@link #OBJECT OBJECT} or {@link #METHOD
* METHOD}.
*/
public int getSort() {
return sort;
}
/**
* Returns the number of dimensions of this array type. This method should
* only be used for an array type.
*
* @return the number of dimensions of this array type.
*/
public int getDimensions() {
int i = 1;
while (buf[off + i] == '[') {
++i;
}
return i;
}
/**
* Returns the type of the elements of this array type. This method should
* only be used for an array type.
*
* @return Returns the type of the elements of this array type.
*/
public Type getElementType() {
return getType(buf, off + getDimensions());
}
/**
* Returns the binary name of the class corresponding to this type. This
* method must not be used on method types.
*
* @return the binary name of the class corresponding to this type.
*/
public String getClassName() {
switch (sort) {
case VOID:
return "void";
case BOOLEAN:
return "boolean";
case CHAR:
return "char";
case BYTE:
return "byte";
case SHORT:
return "short";
case INT:
return "int";
case FLOAT:
return "float";
case LONG:
return "long";
case DOUBLE:
return "double";
case ARRAY:
StringBuilder sb = new StringBuilder(getElementType().getClassName());
for (int i = getDimensions(); i > 0; --i) {
sb.append("[]");
}
return sb.toString();
case OBJECT:
return new String(buf, off, len).replace('/', '.');
default:
return null;
}
}
/**
* Returns the internal name of the class corresponding to this object or
* array type. The internal name of a class is its fully qualified name (as
* returned by Class.getName(), where '.' are replaced by '/'. This method
* should only be used for an object or array type.
*
* @return the internal name of the class corresponding to this object type.
*/
public String getInternalName() {
return new String(buf, off, len);
}
/**
* Returns the argument types of methods of this type. This method should
* only be used for method types.
*
* @return the argument types of methods of this type.
*/
public Type[] getArgumentTypes() {
return getArgumentTypes(getDescriptor());
}
/**
* Returns the return type of methods of this type. This method should only
* be used for method types.
*
* @return the return type of methods of this type.
*/
public Type getReturnType() {
return getReturnType(getDescriptor());
}
/**
* Returns the size of the arguments and of the return value of methods of
* this type. This method should only be used for method types.
*
* @return the size of the arguments (plus one for the implicit this
* argument), argSize, and the size of the return value, retSize,
* packed into a single
* int i = <tt>(argSize &lt;&lt; 2) | retSize</tt>
* (argSize is therefore equal to <tt>i &gt;&gt; 2</tt>,
* and retSize to <tt>i &amp; 0x03</tt>).
*/
public int getArgumentsAndReturnSizes() {
return getArgumentsAndReturnSizes(getDescriptor());
}
// ------------------------------------------------------------------------
// Conversion to type descriptors
// ------------------------------------------------------------------------
/**
* Returns the descriptor corresponding to this Java type.
*
* @return the descriptor corresponding to this Java type.
*/
public String getDescriptor() {
StringBuilder buf = new StringBuilder();
getDescriptor(buf);
return buf.toString();
}
/**
* Returns the descriptor corresponding to the given argument and return
* types.
*
* @param returnType
* the return type of the method.
* @param argumentTypes
* the argument types of the method.
* @return the descriptor corresponding to the given argument and return
* types.
*/
public static String getMethodDescriptor(final Type returnType,
final Type... argumentTypes) {
StringBuilder buf = new StringBuilder();
buf.append('(');
for (int i = 0; i < argumentTypes.length; ++i) {
argumentTypes[i].getDescriptor(buf);
}
buf.append(')');
returnType.getDescriptor(buf);
return buf.toString();
}
/**
* Appends the descriptor corresponding to this Java type to the given
* string buffer.
*
* @param buf
* the string buffer to which the descriptor must be appended.
*/
private void getDescriptor(final StringBuilder buf) {
if (this.buf == null) {
// descriptor is in byte 3 of 'off' for primitive types (buf ==
// null)
buf.append((char) ((off & 0xFF000000) >>> 24));
} else if (sort == OBJECT) {
buf.append('L');
buf.append(this.buf, off, len);
buf.append(';');
} else { // sort == ARRAY || sort == METHOD
buf.append(this.buf, off, len);
}
}
// ------------------------------------------------------------------------
// Direct conversion from classes to type descriptors,
// without intermediate Type objects
// ------------------------------------------------------------------------
/**
* Returns the internal name of the given class. The internal name of a
* class is its fully qualified name, as returned by Class.getName(), where
* '.' are replaced by '/'.
*
* @param c
* an object or array class.
* @return the internal name of the given class.
*/
public static String getInternalName(final Class<?> c) {
return c.getName().replace('.', '/');
}
/**
* Returns the descriptor corresponding to the given Java type.
*
* @param c
* an object class, a primitive class or an array class.
* @return the descriptor corresponding to the given class.
*/
public static String getDescriptor(final Class<?> c) {
StringBuilder buf = new StringBuilder();
getDescriptor(buf, c);
return buf.toString();
}
/**
* Returns the descriptor corresponding to the given constructor.
*
* @param c
* a {@link Constructor Constructor} object.
* @return the descriptor of the given constructor.
*/
public static String getConstructorDescriptor(final Constructor<?> c) {
Class<?>[] parameters = c.getParameterTypes();
StringBuilder buf = new StringBuilder();
buf.append('(');
for (int i = 0; i < parameters.length; ++i) {
getDescriptor(buf, parameters[i]);
}
return buf.append(")V").toString();
}
/**
* Returns the descriptor corresponding to the given method.
*
* @param m
* a {@link Method Method} object.
* @return the descriptor of the given method.
*/
public static String getMethodDescriptor(final Method m) {
Class<?>[] parameters = m.getParameterTypes();
StringBuilder buf = new StringBuilder();
buf.append('(');
for (int i = 0; i < parameters.length; ++i) {
getDescriptor(buf, parameters[i]);
}
buf.append(')');
getDescriptor(buf, m.getReturnType());
return buf.toString();
}
/**
* Appends the descriptor of the given class to the given string buffer.
*
* @param buf
* the string buffer to which the descriptor must be appended.
* @param c
* the class whose descriptor must be computed.
*/
private static void getDescriptor(final StringBuilder buf, final Class<?> c) {
Class<?> d = c;
while (true) {
if (d.isPrimitive()) {
char car;
if (d == Integer.TYPE) {
car = 'I';
} else if (d == Void.TYPE) {
car = 'V';
} else if (d == Boolean.TYPE) {
car = 'Z';
} else if (d == Byte.TYPE) {
car = 'B';
} else if (d == Character.TYPE) {
car = 'C';
} else if (d == Short.TYPE) {
car = 'S';
} else if (d == Double.TYPE) {
car = 'D';
} else if (d == Float.TYPE) {
car = 'F';
} else /* if (d == Long.TYPE) */{
car = 'J';
}
buf.append(car);
return;
} else if (d.isArray()) {
buf.append('[');
d = d.getComponentType();
} else {
buf.append('L');
String name = d.getName();
int len = name.length();
for (int i = 0; i < len; ++i) {
char car = name.charAt(i);
buf.append(car == '.' ? '/' : car);
}
buf.append(';');
return;
}
}
}
// ------------------------------------------------------------------------
// Corresponding size and opcodes
// ------------------------------------------------------------------------
/**
* Returns the size of values of this type. This method must not be used for
* method types.
*
* @return the size of values of this type, i.e., 2 for <tt>long</tt> and
* <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise.
*/
public int getSize() {
// the size is in byte 0 of 'off' for primitive types (buf == null)
return buf == null ? (off & 0xFF) : 1;
}
/**
* Returns a JVM instruction opcode adapted to this Java type. This method
* must not be used for method types.
*
* @param opcode
* a JVM instruction opcode. This opcode must be one of ILOAD,
* ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG,
* ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
* @return an opcode that is similar to the given opcode, but adapted to
* this Java type. For example, if this type is <tt>float</tt> and
* <tt>opcode</tt> is IRETURN, this method returns FRETURN.
*/
public int getOpcode(final int opcode) {
if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
// the offset for IALOAD or IASTORE is in byte 1 of 'off' for
// primitive types (buf == null)
return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4);
} else {
// the offset for other instructions is in byte 2 of 'off' for
// primitive types (buf == null)
return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4);
}
}
// ------------------------------------------------------------------------
// Equals, hashCode and toString
// ------------------------------------------------------------------------
/**
* Tests if the given object is equal to this type.
*
* @param o
* the object to be compared to this type.
* @return <tt>true</tt> if the given object is equal to this type.
*/
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Type)) {
return false;
}
Type t = (Type) o;
if (sort != t.sort) {
return false;
}
if (sort >= ARRAY) {
if (len != t.len) {
return false;
}
for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
if (buf[i] != t.buf[j]) {
return false;
}
}
}
return true;
}
/**
* Returns a hash code value for this type.
*
* @return a hash code value for this type.
*/
@Override
public int hashCode() {
int hc = 13 * sort;
if (sort >= ARRAY) {
for (int i = off, end = i + len; i < end; i++) {
hc = 17 * (hc + buf[i]);
}
}
return hc;
}
/**
* Returns a string representation of this type.
*
* @return the descriptor of this type.
*/
@Override
public String toString() {
return getDescriptor();
}
}

View File

@@ -0,0 +1,225 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2013 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* The path to a type argument, wildcard bound, array element type, or static
* inner type within an enclosing type.
*
* @author Eric Bruneton
*/
public class TypePath {
/**
* A type path step that steps into the element type of an array type. See
* {@link #getStep getStep}.
*/
public final static int ARRAY_ELEMENT = 0;
/**
* A type path step that steps into the nested type of a class type. See
* {@link #getStep getStep}.
*/
public final static int INNER_TYPE = 1;
/**
* A type path step that steps into the bound of a wildcard type. See
* {@link #getStep getStep}.
*/
public final static int WILDCARD_BOUND = 2;
/**
* A type path step that steps into a type argument of a generic type. See
* {@link #getStep getStep}.
*/
public final static int TYPE_ARGUMENT = 3;
/**
* The byte array where the path is stored, in Java class file format.
*/
byte[] b;
/**
* The offset of the first byte of the type path in 'b'.
*/
int offset;
/**
* Creates a new type path.
*
* @param b
* the byte array containing the type path in Java class file
* format.
* @param offset
* the offset of the first byte of the type path in 'b'.
*/
TypePath(byte[] b, int offset) {
this.b = b;
this.offset = offset;
}
/**
* Returns the length of this path.
*
* @return the length of this path.
*/
public int getLength() {
return b[offset];
}
/**
* Returns the value of the given step of this path.
*
* @param index
* an index between 0 and {@link #getLength()}, exclusive.
* @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE
* INNER_TYPE}, {@link #WILDCARD_BOUND WILDCARD_BOUND}, or
* {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
*/
public int getStep(int index) {
return b[offset + 2 * index + 1];
}
/**
* Returns the index of the type argument that the given step is stepping
* into. This method should only be used for steps whose value is
* {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
*
* @param index
* an index between 0 and {@link #getLength()}, exclusive.
* @return the index of the type argument that the given step is stepping
* into.
*/
public int getStepArgument(int index) {
return b[offset + 2 * index + 2];
}
/**
* Converts a type path in string form, in the format used by
* {@link #toString()}, into a TypePath object.
*
* @param typePath
* a type path in string form, in the format used by
* {@link #toString()}. May be null or empty.
* @return the corresponding TypePath object, or null if the path is empty.
*/
public static TypePath fromString(final String typePath) {
if (typePath == null || typePath.length() == 0) {
return null;
}
int n = typePath.length();
ByteVector out = new ByteVector(n);
out.putByte(0);
for (int i = 0; i < n;) {
char c = typePath.charAt(i++);
if (c == '[') {
out.put11(ARRAY_ELEMENT, 0);
} else if (c == '.') {
out.put11(INNER_TYPE, 0);
} else if (c == '*') {
out.put11(WILDCARD_BOUND, 0);
} else if (c >= '0' && c <= '9') {
int typeArg = c - '0';
while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') {
typeArg = typeArg * 10 + c - '0';
i += 1;
}
if (i < n && typePath.charAt(i) == ';') {
i += 1;
}
out.put11(TYPE_ARGUMENT, typeArg);
}
}
out.data[0] = (byte) (out.length / 2);
return new TypePath(out.data, 0);
}
/**
* Returns a string representation of this type path. {@link #ARRAY_ELEMENT
* ARRAY_ELEMENT} steps are represented with '[', {@link #INNER_TYPE
* INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps
* with '*' and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type
* argument index in decimal form followed by ';'.
*/
@Override
public String toString() {
int length = getLength();
StringBuilder result = new StringBuilder(length * 2);
for (int i = 0; i < length; ++i) {
switch (getStep(i)) {
case ARRAY_ELEMENT:
result.append('[');
break;
case INNER_TYPE:
result.append('.');
break;
case WILDCARD_BOUND:
result.append('*');
break;
case TYPE_ARGUMENT:
result.append(getStepArgument(i)).append(';');
break;
default:
result.append('_');
}
}
return result.toString();
}
}

View File

@@ -0,0 +1,481 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2013 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.redkale.asm;
/**
* A reference to a type appearing in a class, field or method declaration, or
* on an instruction. Such a reference designates the part of the class where
* the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws'
* clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable
* declaration, etc).
*
* @author Eric Bruneton
*/
public class TypeReference {
/**
* The sort of type references that target a type parameter of a generic
* class. See {@link #getSort getSort}.
*/
public final static int CLASS_TYPE_PARAMETER = 0x00;
/**
* The sort of type references that target a type parameter of a generic
* method. See {@link #getSort getSort}.
*/
public final static int METHOD_TYPE_PARAMETER = 0x01;
/**
* The sort of type references that target the super class of a class or one
* of the interfaces it implements. See {@link #getSort getSort}.
*/
public final static int CLASS_EXTENDS = 0x10;
/**
* The sort of type references that target a bound of a type parameter of a
* generic class. See {@link #getSort getSort}.
*/
public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11;
/**
* The sort of type references that target a bound of a type parameter of a
* generic method. See {@link #getSort getSort}.
*/
public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12;
/**
* The sort of type references that target the type of a field. See
* {@link #getSort getSort}.
*/
public final static int FIELD = 0x13;
/**
* The sort of type references that target the return type of a method. See
* {@link #getSort getSort}.
*/
public final static int METHOD_RETURN = 0x14;
/**
* The sort of type references that target the receiver type of a method.
* See {@link #getSort getSort}.
*/
public final static int METHOD_RECEIVER = 0x15;
/**
* The sort of type references that target the type of a formal parameter of
* a method. See {@link #getSort getSort}.
*/
public final static int METHOD_FORMAL_PARAMETER = 0x16;
/**
* The sort of type references that target the type of an exception declared
* in the throws clause of a method. See {@link #getSort getSort}.
*/
public final static int THROWS = 0x17;
/**
* The sort of type references that target the type of a local variable in a
* method. See {@link #getSort getSort}.
*/
public final static int LOCAL_VARIABLE = 0x40;
/**
* The sort of type references that target the type of a resource variable
* in a method. See {@link #getSort getSort}.
*/
public final static int RESOURCE_VARIABLE = 0x41;
/**
* The sort of type references that target the type of the exception of a
* 'catch' clause in a method. See {@link #getSort getSort}.
*/
public final static int EXCEPTION_PARAMETER = 0x42;
/**
* The sort of type references that target the type declared in an
* 'instanceof' instruction. See {@link #getSort getSort}.
*/
public final static int INSTANCEOF = 0x43;
/**
* The sort of type references that target the type of the object created by
* a 'new' instruction. See {@link #getSort getSort}.
*/
public final static int NEW = 0x44;
/**
* The sort of type references that target the receiver type of a
* constructor reference. See {@link #getSort getSort}.
*/
public final static int CONSTRUCTOR_REFERENCE = 0x45;
/**
* The sort of type references that target the receiver type of a method
* reference. See {@link #getSort getSort}.
*/
public final static int METHOD_REFERENCE = 0x46;
/**
* The sort of type references that target the type declared in an explicit
* or implicit cast instruction. See {@link #getSort getSort}.
*/
public final static int CAST = 0x47;
/**
* The sort of type references that target a type parameter of a generic
* constructor in a constructor call. See {@link #getSort getSort}.
*/
public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
/**
* The sort of type references that target a type parameter of a generic
* method in a method call. See {@link #getSort getSort}.
*/
public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
/**
* The sort of type references that target a type parameter of a generic
* constructor in a constructor reference. See {@link #getSort getSort}.
*/
public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;
/**
* The sort of type references that target a type parameter of a generic
* method in a method reference. See {@link #getSort getSort}.
*/
public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
/**
* The type reference value in Java class file format.
*/
private int value;
/**
* Creates a new TypeReference.
*
* @param typeRef
* the int encoded value of the type reference, as received in a
* visit method related to type annotations, like
* visitTypeAnnotation.
*/
public TypeReference(int typeRef) {
this.value = typeRef;
}
/**
* Returns a type reference of the given sort.
*
* @param sort
* {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
* {@link #METHOD_RECEIVER METHOD_RECEIVER},
* {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
* {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
* {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
* {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or
* {@link #METHOD_REFERENCE METHOD_REFERENCE}.
* @return a type reference of the given sort.
*/
public static TypeReference newTypeReference(int sort) {
return new TypeReference(sort << 24);
}
/**
* Returns a reference to a type parameter of a generic class or method.
*
* @param sort
* {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
* @param paramIndex
* the type parameter index.
* @return a reference to the given generic class or method type parameter.
*/
public static TypeReference newTypeParameterReference(int sort,
int paramIndex) {
return new TypeReference((sort << 24) | (paramIndex << 16));
}
/**
* Returns a reference to a type parameter bound of a generic class or
* method.
*
* @param sort
* {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
* @param paramIndex
* the type parameter index.
* @param boundIndex
* the type bound index within the above type parameters.
* @return a reference to the given generic class or method type parameter
* bound.
*/
public static TypeReference newTypeParameterBoundReference(int sort,
int paramIndex, int boundIndex) {
return new TypeReference((sort << 24) | (paramIndex << 16)
| (boundIndex << 8));
}
/**
* Returns a reference to the super class or to an interface of the
* 'implements' clause of a class.
*
* @param itfIndex
* the index of an interface in the 'implements' clause of a
* class, or -1 to reference the super class of the class.
* @return a reference to the given super type of a class.
*/
public static TypeReference newSuperTypeReference(int itfIndex) {
itfIndex &= 0xFFFF;
return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8));
}
/**
* Returns a reference to the type of a formal parameter of a method.
*
* @param paramIndex
* the formal parameter index.
*
* @return a reference to the type of the given method formal parameter.
*/
public static TypeReference newFormalParameterReference(int paramIndex) {
return new TypeReference((METHOD_FORMAL_PARAMETER << 24)
| (paramIndex << 16));
}
/**
* Returns a reference to the type of an exception, in a 'throws' clause of
* a method.
*
* @param exceptionIndex
* the index of an exception in a 'throws' clause of a method.
*
* @return a reference to the type of the given exception.
*/
public static TypeReference newExceptionReference(int exceptionIndex) {
return new TypeReference((THROWS << 24) | (exceptionIndex << 8));
}
/**
* Returns a reference to the type of the exception declared in a 'catch'
* clause of a method.
*
* @param tryCatchBlockIndex
* the index of a try catch block (using the order in which they
* are visited with visitTryCatchBlock).
*
* @return a reference to the type of the given exception.
*/
public static TypeReference newTryCatchReference(int tryCatchBlockIndex) {
return new TypeReference((EXCEPTION_PARAMETER << 24)
| (tryCatchBlockIndex << 8));
}
/**
* Returns a reference to the type of a type argument in a constructor or
* method call or reference.
*
* @param sort
* {@link #CAST CAST},
* {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT
* METHOD_INVOCATION_TYPE_ARGUMENT},
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT
* METHOD_REFERENCE_TYPE_ARGUMENT}.
* @param argIndex
* the type argument index.
*
* @return a reference to the type of the given type argument.
*/
public static TypeReference newTypeArgumentReference(int sort, int argIndex) {
return new TypeReference((sort << 24) | argIndex);
}
/**
* Returns the sort of this type reference.
*
* @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
* {@link #CLASS_EXTENDS CLASS_EXTENDS},
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND},
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND},
* {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
* {@link #METHOD_RECEIVER METHOD_RECEIVER},
* {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER},
* {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
* {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
* {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER},
* {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
* {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE},
* {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST},
* {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT
* METHOD_INVOCATION_TYPE_ARGUMENT},
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT
* METHOD_REFERENCE_TYPE_ARGUMENT}.
*/
public int getSort() {
return value >>> 24;
}
/**
* Returns the index of the type parameter referenced by this type
* reference. This method must only be used for type references whose sort
* is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
*
* @return a type parameter index.
*/
public int getTypeParameterIndex() {
return (value & 0x00FF0000) >> 16;
}
/**
* Returns the index of the type parameter bound, within the type parameter
* {@link #getTypeParameterIndex}, referenced by this type reference. This
* method must only be used for type references whose sort is
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
*
* @return a type parameter bound index.
*/
public int getTypeParameterBoundIndex() {
return (value & 0x0000FF00) >> 8;
}
/**
* Returns the index of the "super type" of a class that is referenced by
* this type reference. This method must only be used for type references
* whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}.
*
* @return the index of an interface in the 'implements' clause of a class,
* or -1 if this type reference references the type of the super
* class.
*/
public int getSuperTypeIndex() {
return (short) ((value & 0x00FFFF00) >> 8);
}
/**
* Returns the index of the formal parameter whose type is referenced by
* this type reference. This method must only be used for type references
* whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}.
*
* @return a formal parameter index.
*/
public int getFormalParameterIndex() {
return (value & 0x00FF0000) >> 16;
}
/**
* Returns the index of the exception, in a 'throws' clause of a method,
* whose type is referenced by this type reference. This method must only be
* used for type references whose sort is {@link #THROWS THROWS}.
*
* @return the index of an exception in the 'throws' clause of a method.
*/
public int getExceptionIndex() {
return (value & 0x00FFFF00) >> 8;
}
/**
* Returns the index of the try catch block (using the order in which they
* are visited with visitTryCatchBlock), whose 'catch' type is referenced by
* this type reference. This method must only be used for type references
* whose sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} .
*
* @return the index of an exception in the 'throws' clause of a method.
*/
public int getTryCatchBlockIndex() {
return (value & 0x00FFFF00) >> 8;
}
/**
* Returns the index of the type argument referenced by this type reference.
* This method must only be used for type references whose sort is
* {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT},
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.
*
* @return a type parameter index.
*/
public int getTypeArgumentIndex() {
return value & 0xFF;
}
/**
* Returns the int encoded value of this type reference, suitable for use in
* visit methods related to type annotations, like visitTypeAnnotation.
*
* @return the int encoded value of this type reference.
*/
public int getValue() {
return value;
}
}

View File

@@ -0,0 +1,27 @@
need copy classes:
AnnotationVisitor.java
AnnotationWriter.java
Attribute.java
ByteVector.java
ClassReader.java
ClassVisitor.java
ClassWriter.java
Context.java
CurrentFrame.java
Edge.java
FieldVisitor.java
FieldWriter.java
Frame.java
Handle.java
Handler.java
Item.java
Label.java
MethodVisitor.java
MethodWriter.java
ModuleVisitor.java
ModuleWriter.java
Opcodes.java
Type.java
TypePath.java
TypeReference.java

View File

@@ -0,0 +1,4 @@
/**
* 本包下所有代码均是从/java.base/jdk/internal/org/objectweb/asm 拷贝过来的
*/
package org.redkale.asm;

View File

@@ -89,6 +89,8 @@ public final class ApiDocsService {
for (final Class rtype : action.results()) {
results.add(rtype.getName());
if (typesmap.containsKey(rtype.getName())) continue;
if(rtype.getName().startsWith("java.")) continue;
if(rtype.getName().startsWith("javax.")) continue;
final boolean filter = FilterBean.class.isAssignableFrom(rtype);
final Map<String, Map<String, Object>> typemap = new LinkedHashMap<>();
Class loop = rtype;
@@ -136,6 +138,8 @@ public final class ApiDocsService {
paramsList.add(parammap);
if (ptype.isPrimitive() || ptype == String.class) continue;
if (typesmap.containsKey(ptype.getName())) continue;
if(ptype.getName().startsWith("java.")) continue;
if(ptype.getName().startsWith("javax.")) continue;
final Map<String, Map<String, Object>> typemap = new LinkedHashMap<>();
Class loop = ptype;
@@ -192,7 +196,7 @@ public final class ApiDocsService {
final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "apidoc.json"));
out.write(json.getBytes("UTF-8"));
out.close();
File doctemplate = new File(app.getHome(), "conf/apidoc-template.html");
File doctemplate = new File(app.getConfPath(), "apidoc-template.html");
InputStream in = null;
if (doctemplate.isFile() && doctemplate.canRead()) {
in = new FileInputStream(doctemplate);

View File

@@ -18,6 +18,7 @@ import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.logging.*;
import javax.annotation.Resource;
import javax.net.ssl.SSLContext;
import javax.xml.parsers.*;
import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.convert.Convert;
@@ -44,8 +45,6 @@ import org.w3c.dom.*;
* 4、最后进行Service、Servlet与其他资源之间的依赖注入
* </pre>
* <p>
* 编译时需要加入: -XDignore.symbol.file=true
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
@@ -62,6 +61,11 @@ public final class Application {
*/
public static final String RESNAME_APP_HOME = "APP_HOME";
/**
* 当前进程的配置目录如果不是绝对路径则视为HOME目录下的相对路径 类型String、File、Path
*/
public static final String RESNAME_APP_CONF = "APP_CONF";
/**
* application.xml 文件中resources节点的内容 类型: AnyValue
*/
@@ -92,6 +96,16 @@ public final class Application {
*/
public static final String RESNAME_SERVER_ROOT = Server.RESNAME_SERVER_ROOT;
/**
* 当前Server的线程池
*/
public static final String RESNAME_SERVER_EXECUTOR = Server.RESNAME_SERVER_EXECUTOR;
/**
* 当前Server的ResourceFactory
*/
public static final String RESNAME_SERVER_RESFACTORY = Server.RESNAME_SERVER_RESFACTORY;
//本地IP地址
final InetAddress localAddress;
@@ -104,8 +118,8 @@ public final class Application {
//NodeServer 资源
final List<NodeServer> servers = new CopyOnWriteArrayList<>();
//传输端的TransportFactory
final TransportFactory transportFactory;
//SNCP传输端的TransportFactory, 注意: 只给SNCP使用
final TransportFactory sncpTransportFactory;
//全局根ResourceFactory
final ResourceFactory resourceFactory = ResourceFactory.root();
@@ -121,16 +135,22 @@ public final class Application {
//--------------------------------------------------------------------------------------------
//是否用于main方法运行
private final boolean singletonrun;
final boolean singletonrun;
//根WatchFactory
//private final WatchFactory watchFactory = WatchFactory.root();
//进程根目录
private final File home;
//配置文件目录
private final File confPath;
//日志
private final Logger logger;
//监听事件
private final List<ApplicationListener> listeners = new CopyOnWriteArrayList<>();
//服务启动时间
private final long startTime = System.currentTimeMillis();
@@ -150,6 +170,7 @@ public final class Application {
private Application(final boolean singletonrun, final AnyValue config) {
this.singletonrun = singletonrun;
this.config = config;
System.setProperty("redkale.version", Redkale.getDotedVersion());
final File root = new File(System.getProperty(RESNAME_APP_HOME));
this.resourceFactory.register(RESNAME_APP_TIME, long.class, this.startTime);
@@ -158,6 +179,12 @@ public final class Application {
try {
this.resourceFactory.register(RESNAME_APP_HOME, root.getCanonicalPath());
this.home = root.getCanonicalFile();
String confsubpath = System.getProperty(RESNAME_APP_CONF, "conf");
if (confsubpath.charAt(0) == '/' || confsubpath.indexOf(':') > 0) {
this.confPath = new File(confsubpath).getCanonicalFile();
} else {
this.confPath = new File(this.home, confsubpath).getCanonicalFile();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -182,7 +209,7 @@ public final class Application {
System.setProperty(RESNAME_APP_NODE, node);
}
//以下是初始化日志配置
final File logconf = new File(root, "conf/logging.properties");
final File logconf = new File(confPath, "logging.properties");
if (logconf.isFile() && logconf.canRead()) {
try {
final String rootpath = root.getCanonicalPath().replace('\\', '/');
@@ -233,27 +260,34 @@ public final class Application {
this.logger = Logger.getLogger(this.getClass().getSimpleName());
this.serversLatch = new CountDownLatch(config.getAnyValues("server").length + 1);
this.classLoader = new RedkaleClassLoader(Thread.currentThread().getContextClassLoader());
logger.log(Level.INFO, "------------------------------- Redkale " + Redkale.getDotedVersion() + " -------------------------------");
logger.log(Level.INFO, "------------------------- Redkale " + Redkale.getDotedVersion() + " -------------------------");
//------------------配置 <transport> 节点 ------------------
ObjectPool<ByteBuffer> transportPool = null;
ExecutorService transportExec = null;
AsynchronousChannelGroup transportGroup = null;
final AnyValue resources = config.getAnyValue("resources");
TransportStrategy strategy = null;
int bufferCapacity = 32 * 1024;
int bufferPoolSize = Runtime.getRuntime().availableProcessors() * 8;
int readTimeoutSeconds = TransportFactory.DEFAULT_READTIMEOUTSECONDS;
int writeTimeoutSeconds = TransportFactory.DEFAULT_WRITETIMEOUTSECONDS;
AtomicLong createBufferCounter = new AtomicLong();
AtomicLong cycleBufferCounter = new AtomicLong();
if (resources != null) {
AnyValue transportConf = resources.getAnyValue("transport");
int groupsize = resources.getAnyValues("group").length;
if (groupsize > 0 && transportConf == null) transportConf = new DefaultAnyValue();
if (transportConf != null) {
//--------------transportBufferPool-----------
AtomicLong createBufferCounter = new AtomicLong();
AtomicLong cycleBufferCounter = new AtomicLong();
final int bufferCapacity = Math.max(parseLenth(transportConf.getValue("bufferCapacity"), 8 * 1024), 4 * 1024);
final int bufferPoolSize = parseLenth(transportConf.getValue("bufferPoolSize"), groupsize * Runtime.getRuntime().availableProcessors() * 8);
final int threads = parseLenth(transportConf.getValue("threads"), groupsize * Runtime.getRuntime().availableProcessors() * 8);
bufferCapacity = Math.max(parseLenth(transportConf.getValue("bufferCapacity"), bufferCapacity), 8 * 1024);
readTimeoutSeconds = transportConf.getIntValue("readTimeoutSeconds", readTimeoutSeconds);
writeTimeoutSeconds = transportConf.getIntValue("writeTimeoutSeconds", writeTimeoutSeconds);
final int threads = parseLenth(transportConf.getValue("threads"), groupsize * Runtime.getRuntime().availableProcessors() * 2);
bufferPoolSize = parseLenth(transportConf.getValue("bufferPoolSize"), threads * 4);
final int capacity = bufferCapacity;
transportPool = new ObjectPool<>(createBufferCounter, cycleBufferCounter, bufferPoolSize,
(Object... params) -> ByteBuffer.allocateDirect(bufferCapacity), null, (e) -> {
if (e == null || e.isReadOnly() || e.capacity() != bufferCapacity) return false;
(Object... params) -> ByteBuffer.allocateDirect(capacity), null, (e) -> {
if (e == null || e.isReadOnly() || e.capacity() != capacity) return false;
e.clear();
return true;
});
@@ -261,7 +295,7 @@ public final class Application {
try {
final String strategyClass = transportConf.getValue("strategy");
if (strategyClass != null && !strategyClass.isEmpty()) {
strategy = (TransportStrategy) classLoader.loadClass(strategyClass).newInstance();
strategy = (TransportStrategy) classLoader.loadClass(strategyClass).getDeclaredConstructor().newInstance();
}
final AtomicInteger counter = new AtomicInteger();
transportExec = Executors.newFixedThreadPool(threads, (Runnable r) -> {
@@ -274,10 +308,37 @@ public final class Application {
} catch (Exception e) {
throw new RuntimeException(e);
}
logger.log(Level.INFO, Transport.class.getSimpleName() + " configure bufferCapacity = " + bufferCapacity + "; bufferPoolSize = " + bufferPoolSize + "; threads = " + threads + ";");
logger.log(Level.INFO, Transport.class.getSimpleName() + " configure bufferCapacity = " + bufferCapacity / 1024 + "K; bufferPoolSize = " + bufferPoolSize + "; threads = " + threads + ";");
}
}
this.transportFactory = new TransportFactory(transportExec, transportPool, transportGroup, strategy);
if (transportGroup == null) {
final AtomicInteger counter = new AtomicInteger();
transportExec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 8, (Runnable r) -> {
Thread t = new Thread(r);
t.setDaemon(true);
t.setName("Transport-Thread-" + counter.incrementAndGet());
return t;
});
try {
transportGroup = AsynchronousChannelGroup.withCachedThreadPool(transportExec, 1);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
if (transportPool == null) {
final int capacity = bufferCapacity;
transportPool = new ObjectPool<>(createBufferCounter, cycleBufferCounter, bufferPoolSize,
(Object... params) -> ByteBuffer.allocateDirect(capacity), null, (e) -> {
if (e == null || e.isReadOnly() || e.capacity() != capacity) return false;
e.clear();
return true;
});
}
this.sncpTransportFactory = TransportFactory.create(transportExec, transportPool, transportGroup, (SSLContext) null, readTimeoutSeconds, writeTimeoutSeconds, strategy);
DefaultAnyValue tarnsportConf = DefaultAnyValue.create(TransportFactory.NAME_POOLMAXCONNS, System.getProperty("net.transport.poolmaxconns", "100"))
.addValue(TransportFactory.NAME_PINGINTERVAL, System.getProperty("net.transport.pinginterval", "30"))
.addValue(TransportFactory.NAME_CHECKINTERVAL, System.getProperty("net.transport.checkinterval", "30"));
this.sncpTransportFactory.init(tarnsportConf, Sncp.PING_BUFFER, Sncp.PONG_BUFFER.remaining());
Thread.currentThread().setContextClassLoader(this.classLoader);
this.serverClassLoader = new RedkaleClassLoader(this.classLoader);
}
@@ -286,8 +347,8 @@ public final class Application {
return resourceFactory;
}
public TransportFactory getTransportFactory() {
return transportFactory;
public TransportFactory getSncpTransportFactory() {
return sncpTransportFactory;
}
public RedkaleClassLoader getClassLoader() {
@@ -302,10 +363,22 @@ public final class Application {
return new ArrayList<>(servers);
}
public List<DataSource> getDataSources() {
return new ArrayList<>(dataSources);
}
public List<CacheSource> getCacheSources() {
return new ArrayList<>(cacheSources);
}
public File getHome() {
return home;
}
public File getConfPath() {
return confPath;
}
public long getStartTime() {
return startTime;
}
@@ -315,7 +388,9 @@ public final class Application {
}
public void init() throws Exception {
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "" + Runtime.getRuntime().availableProcessors() * 4);
System.setProperty("net.transport.poolmaxconns", "100");
System.setProperty("net.transport.pinginterval", "30");
System.setProperty("net.transport.checkinterval", "30");
System.setProperty("convert.bson.tiny", "true");
System.setProperty("convert.json.tiny", "true");
System.setProperty("convert.bson.pool.size", "128");
@@ -323,12 +398,21 @@ public final class Application {
System.setProperty("convert.bson.writer.buffer.defsize", "4096");
System.setProperty("convert.json.writer.buffer.defsize", "4096");
File persist = new File(this.home, "conf/persistence.xml");
File persist = new File(this.confPath, "persistence.xml");
final String homepath = this.home.getCanonicalPath();
final String confpath = this.confPath.getCanonicalPath();
if (persist.isFile()) System.setProperty(DataSources.DATASOURCE_CONFPATH, persist.getCanonicalPath());
logger.log(Level.INFO, RESNAME_APP_HOME + "= " + homepath + "\r\n" + RESNAME_APP_ADDR + "= " + this.localAddress.getHostAddress());
String lib = config.getValue("lib", "").trim().replace("${APP_HOME}", homepath);
lib = lib.isEmpty() ? (homepath + "/conf") : (lib + ";" + homepath + "/conf");
String pidstr = "";
try { //JDK 9+
Class phclass = Class.forName("java.lang.ProcessHandle");
Object phobj = phclass.getMethod("current").invoke(null);
Object pid = phclass.getMethod("pid").invoke(phobj);
pidstr = "APP_PID = " + pid + "\r\n";
} catch (Throwable t) {
}
logger.log(Level.INFO, pidstr + "APP_JAVA = " + System.getProperty("java.version") + "\r\n" + RESNAME_APP_ADDR + " = " + this.localAddress.getHostAddress() + "\r\n" + RESNAME_APP_HOME + " = " + homepath + "\r\n" + RESNAME_APP_CONF + " = " + confpath);
String lib = config.getValue("lib", "${APP_HOME}/libs/*").trim().replace("${APP_HOME}", homepath);
lib = lib.isEmpty() ? confpath : (lib + ";" + confpath);
Server.loadLib(classLoader, logger, lib);
//------------------------------------------------------------------------
@@ -341,14 +425,13 @@ public final class Application {
if (dfloads != null) {
for (String dfload : dfloads.split(";")) {
if (dfload.trim().isEmpty()) continue;
dfload = dfload.trim().replace("${APP_HOME}", home.getCanonicalPath()).replace('\\', '/');
final File df = (dfload.indexOf('/') < 0) ? new File(home, "conf/" + dfload) : new File(dfload);
final File df = (dfload.indexOf('/') < 0) ? new File(confPath, "/" + dfload) : new File(dfload);
if (df.isFile()) {
Properties ps = new Properties();
InputStream in = new FileInputStream(df);
ps.load(in);
in.close();
ps.forEach((x, y) -> resourceFactory.register("property." + x, y));
ps.forEach((x, y) -> resourceFactory.register("property." + x, y.toString().replace("${APP_HOME}", homepath)));
}
}
}
@@ -356,7 +439,7 @@ public final class Application {
String name = prop.getValue("name");
String value = prop.getValue("value");
if (name == null || value == null) continue;
value = value.replace("${APP_HOME}", home.getCanonicalPath()).replace('\\', '/');
value = value.replace("${APP_HOME}", homepath);
if (name.startsWith("system.property.")) {
System.setProperty(name.substring("system.property.".length()), value);
} else if (name.startsWith("mimetype.property.")) {
@@ -384,14 +467,15 @@ public final class Application {
try {
Resource res = field.getAnnotation(Resource.class);
if (res == null) return;
if (Sncp.isRemote((Service) src)) return; //远程模式不得注入
if (src instanceof Service && Sncp.isRemote((Service) src)) return; //远程模式不得注入
Class type = field.getType();
if (type == Application.class) {
field.set(src, application);
} else if (type == ResourceFactory.class) {
field.set(src, res.name().equalsIgnoreCase("server") ? rf : (res.name().isEmpty() ? application.resourceFactory : null));
boolean serv = RESNAME_SERVER_RESFACTORY.equals(res.name()) || res.name().equalsIgnoreCase("server");
field.set(src, serv ? rf : (res.name().isEmpty() ? application.resourceFactory : null));
} else if (type == TransportFactory.class) {
field.set(src, application.transportFactory);
field.set(src, application.sncpTransportFactory);
} else if (type == NodeSncpServer.class) {
NodeServer server = null;
for (NodeServer ns : application.getNodeServers()) {
@@ -457,7 +541,17 @@ public final class Application {
final InetSocketAddress addr = new InetSocketAddress(node.getValue("addr"), node.getIntValue("port"));
ginfo.putAddress(addr);
}
transportFactory.addGroupInfo(ginfo);
sncpTransportFactory.addGroupInfo(ginfo);
}
for (AnyValue conf : resources.getAnyValues("listener")) {
final String listenClass = conf.getValue("value", "");
if (listenClass.isEmpty()) continue;
Class clazz = classLoader.loadClass(listenClass);
if (!ApplicationListener.class.isAssignableFrom(clazz)) continue;
@SuppressWarnings("unchecked")
ApplicationListener listener = (ApplicationListener) clazz.getDeclaredConstructor().newInstance();
listener.init(config);
this.listeners.add(listener);
}
}
//------------------------------------------------------------------------
@@ -465,8 +559,8 @@ public final class Application {
public void restoreConfig() throws IOException {
synchronized (this) {
File confFile = new File(this.home, "conf/application.xml");
confFile.renameTo(new File(this.home, "conf/application_" + String.format("%1$tY%1$tm%1$td%1$tH%1$tM%1$tS", System.currentTimeMillis()) + ".xml"));
File confFile = new File(this.confPath, "application.xml");
confFile.renameTo(new File(this.confPath, "application_" + String.format("%1$tY%1$tm%1$td%1$tH%1$tM%1$tS", System.currentTimeMillis()) + ".xml"));
final PrintStream ps = new PrintStream(new FileOutputStream(confFile));
ps.append(config.toXML("application"));
ps.close();
@@ -547,15 +641,15 @@ public final class Application {
buffer.flip();
channel.write(buffer);
buffer.clear();
channel.configureBlocking(false);
channel.configureBlocking(true);
try {
channel.read(buffer);
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
channel.close();
logger.info(new String(bytes));
Thread.sleep(500);
logger.info("Send: " + command + ", Reply: " + new String(bytes));
Thread.sleep(1000);
} catch (Exception e) {
if (e instanceof PortUnreachableException) {
if ("APIDOC".equalsIgnoreCase(command)) {
@@ -593,10 +687,51 @@ public final class Application {
runServers(timecd, others);
runServers(timecd, watchs); //必须在所有服务都启动后再启动WATCH服务
timecd.await();
//if (!singletonrun) signalHandle();
//if (!singletonrun) clearPersistData();
logger.info(this.getClass().getSimpleName() + " started in " + (System.currentTimeMillis() - startTime) + " ms\r\n");
if (!singletonrun) this.serversLatch.await();
}
// private void clearPersistData() {
// File cachedir = new File(home, "cache");
// if (!cachedir.isDirectory()) return;
// File[] lfs = cachedir.listFiles();
// if (lfs != null) {
// for (File file : lfs) {
// if (file.getName().startsWith("persist-")) file.delete();
// }
// }
// }
// private void signalHandle() {
// //http://www.comptechdoc.org/os/linux/programming/linux_pgsignals.html
// String[] sigs = new String[]{"HUP", "TERM", "INT", "QUIT", "KILL", "TSTP", "USR1", "USR2", "STOP"};
// List<sun.misc.Signal> list = new ArrayList<>();
// for (String sig : sigs) {
// try {
// list.add(new sun.misc.Signal(sig));
// } catch (Exception e) {
// }
// }
// sun.misc.SignalHandler handler = new sun.misc.SignalHandler() {
//
// private volatile boolean runed;
//
// @Override
// public void handle(Signal sig) {
// if (runed) return;
// runed = true;
// logger.info(Application.this.getClass().getSimpleName() + " stoped\r\n");
// System.exit(0);
// }
// };
// for (Signal sig : list) {
// try {
// Signal.handle(sig, handler);
// } catch (Exception e) {
// }
// }
// }
@SuppressWarnings("unchecked")
private void runServers(CountDownLatch timecd, final List<AnyValue> serconfs) throws Exception {
this.servicecdl = new CountDownLatch(serconfs.size());
@@ -677,13 +812,22 @@ public final class Application {
sercdl.await();
}
public static <T extends Service> T singleton(Class<T> serviceClass) throws Exception {
return singleton("", serviceClass);
public static <T extends Service> T singleton(Class<T> serviceClass, Class<? extends Service>... extServiceClasses) throws Exception {
return singleton("", serviceClass, extServiceClasses);
}
public static <T extends Service> T singleton(String name, Class<T> serviceClass) throws Exception {
public static <T extends Service> T singleton(String name, Class<T> serviceClass, Class<? extends Service>... extServiceClasses) throws Exception {
if (serviceClass == null) throw new IllegalArgumentException("serviceClass is null");
final Application application = Application.create(true);
System.setProperty("red" + "kale-singleton-serviceclass", serviceClass.getName());
if (extServiceClasses != null && extServiceClasses.length > 0) {
StringBuilder sb = new StringBuilder();
for (Class clazz : extServiceClasses) {
if (sb.length() > 0) sb.append(',');
sb.append(clazz.getName());
}
System.setProperty("red" + "kale-singleton-extserviceclasses", sb.toString());
}
application.init();
application.start();
for (NodeServer server : application.servers) {
@@ -696,10 +840,17 @@ public final class Application {
}
public static Application create(final boolean singleton) throws IOException {
final String home = new File(System.getProperty(RESNAME_APP_HOME, "")).getCanonicalPath();
final String home = new File(System.getProperty(RESNAME_APP_HOME, "")).getCanonicalPath().replace('\\', '/');
System.setProperty(RESNAME_APP_HOME, home);
File appfile = new File(home, "conf/application.xml");
return new Application(singleton, load(new FileInputStream(appfile)));
String confsubpath = System.getProperty(RESNAME_APP_CONF, "conf");
File appfile;
if (confsubpath.charAt(0) == '/' || confsubpath.indexOf(':') > 0) {
appfile = new File(confsubpath).getCanonicalFile();
} else {
appfile = new File(new File(home), confsubpath);
}
File appconf = new File(appfile, "application.xml");
return new Application(singleton, load(new FileInputStream(appconf)));
}
public static void main(String[] args) throws Exception {
@@ -716,6 +867,9 @@ public final class Application {
application.init();
application.startSelfServer();
try {
for (ApplicationListener listener : application.listeners) {
listener.preStart(application);
}
application.start();
} catch (Exception e) {
application.logger.log(Level.SEVERE, "Application start error", e);
@@ -733,7 +887,15 @@ public final class Application {
return null;
}
private void shutdown() throws Exception {
public void shutdown() throws Exception {
for (ApplicationListener listener : this.listeners) {
try {
listener.preShutdown(this);
} catch (Exception e) {
logger.log(Level.WARNING, listener.getClass() + " preShutdown erroneous", e);
}
}
servers.stream().forEach((server) -> {
try {
server.shutdown();
@@ -760,7 +922,7 @@ public final class Application {
logger.log(Level.FINER, source.getClass() + " close CacheSource erroneous", e);
}
}
this.transportFactory.shutdownNow();
this.sncpTransportFactory.shutdownNow();
}
private static int parseLenth(String value, int defValue) {

View File

@@ -0,0 +1,45 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.boot;
import org.redkale.util.AnyValue;
/**
* Application启动和关闭时的监听事件 <br>
* 只能通过application.xml配置
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public interface ApplicationListener {
/**
* 初始化方法
*
* @param config 配置参数
*/
default void init(AnyValue config) {
}
/**
* Application 在运行start前调用
*
* @param application Application
*/
default void preStart(Application application) {
}
/**
* Application 在运行shutdown前调用
*
* @param application Application
*/
default void preShutdown(Application application) {
}
}

View File

@@ -7,10 +7,11 @@ package org.redkale.boot;
import java.io.*;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.lang.reflect.Modifier;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Predicate;
import java.util.jar.*;
import java.util.logging.*;
import java.util.regex.*;
@@ -30,12 +31,14 @@ public final class ClassFilter<T> {
private static final Logger logger = Logger.getLogger(ClassFilter.class.getName()); //日志对象
private static final boolean finer = logger.isLoggable(Level.FINER); //日志级别
private static final boolean finest = logger.isLoggable(Level.FINEST); //日志级别
private final Set<FilterEntry<T>> entrys = new HashSet<>(); //符合条件的结果
private final Set<FilterEntry<T>> expectEntrys = new HashSet<>(); //准备符合条件的结果
private Predicate<String> expectPredicate;
private boolean refused; //是否拒绝所有数据,设置true则其他规则失效,都是拒绝.
private Class superClass; //符合的父类型。不为空时扫描结果的class必须是superClass的子类
@@ -136,10 +139,11 @@ public final class ClassFilter<T> {
*
* @param property AnyValue
* @param clazzname String
* @param url URL
*/
@SuppressWarnings("unchecked")
public final void filter(AnyValue property, String clazzname) {
filter(property, clazzname, true);
public final void filter(AnyValue property, String clazzname, URL url) {
filter(property, clazzname, true, url);
}
/**
@@ -150,6 +154,18 @@ public final class ClassFilter<T> {
* @param autoscan 为true表示自动扫描的 false表示显著调用filter AutoLoad的注解将被忽略
*/
public final void filter(AnyValue property, String clazzname, boolean autoscan) {
filter(property, clazzname, autoscan, null);
}
/**
* 过滤指定的class
*
* @param property application.xml中对应class节点下的property属性项
* @param clazzname class名称
* @param autoscan 为true表示自动扫描的 false表示显著调用filter AutoLoad的注解将被忽略
* @param url URL
*/
public final void filter(AnyValue property, String clazzname, boolean autoscan, URL url) {
boolean r = accept0(property, clazzname);
ClassFilter cf = r ? this : null;
if (r && ands != null) {
@@ -165,7 +181,7 @@ public final class ClassFilter<T> {
}
}
}
if (cf == null || clazzname.startsWith("sun.")) return;
if (cf == null || clazzname.startsWith("sun.") || clazzname.contains("module-info")) return;
try {
Class clazz = classLoader.loadClass(clazzname);
if (!cf.accept(property, clazz, autoscan)) return;
@@ -183,15 +199,16 @@ public final class ClassFilter<T> {
}
AutoLoad auto = (AutoLoad) clazz.getAnnotation(AutoLoad.class);
if (autoscan && auto != null && !auto.value()) { //自动扫描且被标记为@AutoLoad(false)的
if ((expectPredicate != null && expectPredicate.test(clazzname)) || (autoscan && auto != null && !auto.value())) { //自动扫描且被标记为@AutoLoad(false)的
expectEntrys.add(new FilterEntry(clazz, autoscan, true, property));
} else {
entrys.add(new FilterEntry(clazz, autoscan, false, property));
}
} catch (Throwable cfe) {
if (finer && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.")
&& !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.")) {
logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error", cfe);
if (finest && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.")
&& !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.") && !clazzname.startsWith("META-INF")
&& (!(cfe instanceof NoClassDefFoundError) || (cfe instanceof UnsupportedClassVersionError) || ((NoClassDefFoundError) cfe).getMessage().startsWith("java.lang.NoClassDefFoundError: java"))) {
logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error for class: " + clazzname + (url == null ? "" : (" in " + url)), cfe);
}
}
}
@@ -333,6 +350,14 @@ public final class ClassFilter<T> {
this.refused = refused;
}
public Predicate<String> getExpectPredicate() {
return expectPredicate;
}
public void setExpectPredicate(Predicate<String> predicate) {
this.expectPredicate = predicate;
}
public Set<String> getPrivilegeIncludes() {
return privilegeIncludes;
}
@@ -347,6 +372,7 @@ public final class ClassFilter<T> {
public void setPrivilegeExcludes(Set<String> privilegeExcludes) {
this.privilegeExcludes = privilegeExcludes == null || privilegeExcludes.isEmpty() ? null : privilegeExcludes;
}
/**
@@ -502,7 +528,7 @@ public final class ClassFilter<T> {
classes.add(classname);
if (debug) debugstr.append(classname).append("\r\n");
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname);
if (filter != null) filter.filter(null, classname, url);
}
}
}
@@ -511,7 +537,7 @@ public final class ClassFilter<T> {
} else {
for (String classname : classes) {
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname);
if (filter != null) filter.filter(null, classname, url);
}
}
}
@@ -530,14 +556,14 @@ public final class ClassFilter<T> {
classes.add(classname);
if (debug) debugstr.append(classname).append("\r\n");
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname);
if (filter != null) filter.filter(null, classname, url);
}
}
cache.put(url, classes);
} else {
for (String classname : classes) {
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname);
if (filter != null) filter.filter(null, classname, url);
}
}
}
@@ -550,7 +576,9 @@ public final class ClassFilter<T> {
files.add(root);
} else if (root.isDirectory()) {
if (exclude != null && exclude.equals(root)) return;
for (File f : root.listFiles()) {
File[] lfs = root.listFiles();
if (lfs == null) throw new RuntimeException("File(" + root + ") cannot listFiles()");
for (File f : lfs) {
loadClassFiles(exclude, f, files);
}
}

View File

@@ -14,6 +14,7 @@ import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.logging.*;
import java.util.logging.Formatter;
import java.util.regex.Pattern;
/**
* 自定义的日志输出类
@@ -22,6 +23,7 @@ import java.util.logging.Formatter;
*
* @author zhangjx
*/
@SuppressWarnings("unchecked")
public class LogFileHandler extends Handler {
/**
@@ -98,6 +100,8 @@ public class LogFileHandler extends Handler {
private boolean append;
private Pattern denyreg;
private final AtomicLong loglength = new AtomicLong();
private final AtomicLong logunusuallength = new AtomicLong();
@@ -153,6 +157,8 @@ public class LogFileHandler extends Handler {
if (greater.exists()) Files.move(greater.toPath(), new File(logfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
}
Files.move(logfile.toPath(), new File(logfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
} else {
if (logfile.exists() && logfile.length() < 1) logfile.delete();
}
logstream = null;
}
@@ -165,6 +171,8 @@ public class LogFileHandler extends Handler {
if (greater.exists()) Files.move(greater.toPath(), new File(logunusualfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
}
Files.move(logunusualfile.toPath(), new File(logunusualfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
} else {
if (logunusualfile.exists() && logunusualfile.length() < 1) logunusualfile.delete();
}
logunusualstream = null;
}
@@ -233,7 +241,21 @@ public class LogFileHandler extends Handler {
}
String limitstr = manager.getProperty(cname + ".limit");
try {
if (limitstr != null) this.limit = Math.abs(Integer.decode(limitstr));
if (limitstr != null) {
limitstr = limitstr.toUpperCase();
boolean g = limitstr.indexOf('G') > 0;
boolean m = limitstr.indexOf('M') > 0;
boolean k = limitstr.indexOf('K') > 0;
int ls = Math.abs(Integer.decode(limitstr.replace("G", "").replace("M", "").replace("K", "").replace("B", "")));
if (g) {
ls *= 1024 * 1024 * 1024;
} else if (m) {
ls *= 1024 * 1024;
} else if (k) {
ls *= 1024;
}
this.limit = ls;
}
} catch (Exception e) {
}
String countstr = manager.getProperty(cname + ".count");
@@ -258,7 +280,7 @@ public class LogFileHandler extends Handler {
try {
if (filterstr != null) {
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(filterstr);
setFilter((Filter) clz.newInstance());
setFilter((Filter) clz.getDeclaredConstructor().newInstance());
}
} catch (Exception e) {
}
@@ -266,7 +288,7 @@ public class LogFileHandler extends Handler {
try {
if (formatterstr != null) {
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(formatterstr);
setFormatter((Formatter) clz.newInstance());
setFormatter((Formatter) clz.getDeclaredConstructor().newInstance());
}
} catch (Exception e) {
}
@@ -277,6 +299,14 @@ public class LogFileHandler extends Handler {
if (encodingstr != null) setEncoding(encodingstr);
} catch (Exception e) {
}
String denyregstr = manager.getProperty(cname + ".denyreg");
try {
if (denyregstr != null && !denyregstr.trim().isEmpty()) {
denyreg = Pattern.compile(denyregstr);
}
} catch (Exception e) {
}
}
@Override
@@ -293,6 +323,7 @@ public class LogFileHandler extends Handler {
} else {
record.setSourceClassName('[' + Thread.currentThread().getName() + "] " + sourceClassName);
}
if (denyreg != null && denyreg.matcher(record.getMessage()).find()) return;
records.offer(record);
}

View File

@@ -7,10 +7,12 @@ package org.redkale.boot;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.net.InetSocketAddress;
import java.net.*;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Level;
import javax.annotation.Resource;
import javax.annotation.*;
import static org.redkale.boot.Application.RESNAME_SNCP_ADDR;
import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.net.*;
import org.redkale.net.http.*;
@@ -42,7 +44,7 @@ public class NodeHttpServer extends NodeServer {
}
private static Server createServer(Application application, AnyValue serconf) {
return new HttpServer(application.getStartTime());
return new HttpServer(application.getStartTime(), application.getResourceFactory().createChild());
}
public HttpServer getHttpServer() {
@@ -55,16 +57,19 @@ public class NodeHttpServer extends NodeServer {
}
@Override
@SuppressWarnings("unchecked")
protected ClassFilter<Service> createServiceClassFilter() {
return createClassFilter(this.sncpGroup, null, Service.class, new Class[]{org.redkale.watch.WatchService.class}, Annotation.class, "services", "service");
}
@Override
@SuppressWarnings("unchecked")
protected ClassFilter<Filter> createFilterClassFilter() {
return createClassFilter(null, null, HttpFilter.class, new Class[]{WatchFilter.class}, null, "filters", "filter");
}
@Override
@SuppressWarnings("unchecked")
protected ClassFilter<Servlet> createServletClassFilter() {
return createClassFilter(null, WebServlet.class, HttpServlet.class, new Class[]{WatchServlet.class}, null, "servlets", "servlet");
}
@@ -86,6 +91,7 @@ public class NodeHttpServer extends NodeServer {
}
@Override
@SuppressWarnings("unchecked")
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception {
if (httpServer != null) loadHttpServlet(servletFilter, otherFilter);
}
@@ -108,13 +114,18 @@ public class NodeHttpServer extends NodeServer {
if (loader != null) loader.load(sncpResFactory, src, resourceName, field, attachment);
synchronized (regFactory) {
Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
if (sncpResFactory != null && resourceFactory.find(RESNAME_SNCP_ADDR, String.class) == null) {
resourceFactory.register(RESNAME_SNCP_ADDR, InetSocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDR, InetSocketAddress.class));
resourceFactory.register(RESNAME_SNCP_ADDR, SocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDR, SocketAddress.class));
resourceFactory.register(RESNAME_SNCP_ADDR, String.class, sncpResFactory.find(RESNAME_SNCP_ADDR, String.class));
}
if (nodeService == null) {
nodeService = Sncp.createLocalService(serverClassLoader, resourceName, WebSocketNodeService.class, application.getResourceFactory(), application.getTransportFactory(), (InetSocketAddress) null, (Set<String>) null, (AnyValue) null);
nodeService = Sncp.createLocalService(serverClassLoader, resourceName, WebSocketNodeService.class, application.getResourceFactory(), application.getSncpTransportFactory(), (InetSocketAddress) null, (Set<String>) null, (AnyValue) null);
regFactory.register(resourceName, WebSocketNode.class, nodeService);
}
resourceFactory.inject(nodeService, self);
logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService);
field.set(src, nodeService);
logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "WebSocketNode inject error", e);
@@ -122,6 +133,7 @@ public class NodeHttpServer extends NodeServer {
}, WebSocketNode.class);
}
@SuppressWarnings("unchecked")
protected void loadHttpFilter(final AnyValue filtersConf, final ClassFilter<? extends Filter> classFilter) throws Exception {
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
final String threadName = "[" + Thread.currentThread().getName() + "] ";
@@ -129,7 +141,7 @@ public class NodeHttpServer extends NodeServer {
for (FilterEntry<? extends Filter> en : list) {
Class<HttpFilter> clazz = (Class<HttpFilter>) en.getType();
if (Modifier.isAbstract(clazz.getModifiers())) continue;
final HttpFilter filter = clazz.newInstance();
final HttpFilter filter = clazz.getDeclaredConstructor().newInstance();
resourceFactory.inject(filter, this);
DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty();
this.httpServer.addHttpFilter(filter, filterConf);
@@ -138,6 +150,7 @@ public class NodeHttpServer extends NodeServer {
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
}
@SuppressWarnings("unchecked")
protected void loadHttpServlet(final ClassFilter<? extends Servlet> servletFilter, ClassFilter<? extends WebSocket> webSocketFilter) throws Exception {
final AnyValue servletsConf = this.serverConf.getAnyValue("servlets");
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
@@ -150,7 +163,12 @@ public class NodeHttpServer extends NodeServer {
list.sort((FilterEntry<? extends Servlet> o1, FilterEntry<? extends Servlet> o2) -> { //必须保证WebSocketServlet优先加载 因为要确保其他的HttpServlet可以注入本地模式的WebSocketNode
boolean ws1 = WebSocketServlet.class.isAssignableFrom(o1.getType());
boolean ws2 = WebSocketServlet.class.isAssignableFrom(o2.getType());
if (ws1 == ws2) return o1.getType().getName().compareTo(o2.getType().getName());
if (ws1 == ws2) {
Priority p1 = o1.getType().getAnnotation(Priority.class);
Priority p2 = o2.getType().getAnnotation(Priority.class);
int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
return v == 0 ? o1.getType().getName().compareTo(o2.getType().getName()) : 0;
}
return ws1 ? -1 : 1;
});
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
@@ -159,7 +177,7 @@ public class NodeHttpServer extends NodeServer {
if (Modifier.isAbstract(clazz.getModifiers())) continue;
WebServlet ws = clazz.getAnnotation(WebServlet.class);
if (ws == null || ws.value().length == 0) continue;
final HttpServlet servlet = clazz.newInstance();
final HttpServlet servlet = clazz.getDeclaredConstructor().newInstance();
resourceFactory.inject(servlet, this);
final String[] mappings = ws.value();
String pref = ws.repair() ? prefix : "";
@@ -174,7 +192,7 @@ public class NodeHttpServer extends NodeServer {
}
int max = 0;
if (ss != null && sb != null) {
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
ss.sort((AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
if (as.getKey().length() > max) max = as.getKey().length();
}
@@ -195,10 +213,12 @@ public class NodeHttpServer extends NodeServer {
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString().trim());
}
@SuppressWarnings("unchecked")
protected void loadRestServlet(final ClassFilter<? extends WebSocket> webSocketFilter, final AnyValue restConf, final List<Object> restedObjects, final StringBuilder sb) throws Exception {
if (!rest) return;
if (restConf == null) return; //不存在REST服务
final long starts = System.currentTimeMillis();
String prefix0 = restConf.getValue("path", "");
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1);
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0;
@@ -225,35 +245,45 @@ public class NodeHttpServer extends NodeServer {
final ClassFilter restFilter = ClassFilter.create(null, restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues);
final boolean finest = logger.isLoggable(Level.FINEST);
super.interceptorServices.forEach((service) -> {
final Class stype = Sncp.getServiceType(service);
final String name = Sncp.getResourceName(service);
RestService rs = (RestService) stype.getAnnotation(RestService.class);
if (rs == null || rs.ignore()) return;
final CountDownLatch scdl = new CountDownLatch(super.interceptorServices.size());
super.interceptorServices.stream().parallel().forEach((service) -> {
try {
final Class stype = Sncp.getServiceType(service);
final String name = Sncp.getResourceName(service);
RestService rs = (RestService) stype.getAnnotation(RestService.class);
if (rs == null || rs.ignore()) return;
final String stypename = stype.getName();
if (!autoload && !includeValues.contains(stypename)) return;
if (!restFilter.accept(stypename)) return;
if (restedObjects.contains(service)) {
logger.log(Level.WARNING, stype.getName() + " repeat create rest servlet, so ignore");
return;
}
restedObjects.add(service); //避免重复创建Rest对象
HttpServlet servlet = httpServer.addRestServlet(serverClassLoader, service, userType, baseServletType, prefix);
if (servlet == null) return; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null
String prefix2 = prefix;
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) prefix2 = "";
resourceFactory.inject(servlet, NodeHttpServer.this);
if (finest) logger.finest(threadName + " Create RestServlet(resource.name='" + name + "') = " + servlet);
if (ss != null) {
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
for (int i = 0; i < mappings.length; i++) {
mappings[i] = prefix2 + mappings[i];
final String stypename = stype.getName();
if (!autoload && !includeValues.contains(stypename)) return;
if (!restFilter.accept(stypename)) return;
synchronized (restedObjects) {
if (restedObjects.contains(service)) {
logger.log(Level.WARNING, stype.getName() + " repeat create rest servlet, so ignore");
return;
}
restedObjects.add(service); //避免重复创建Rest对象
}
ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName(), mappings));
HttpServlet servlet = httpServer.addRestServlet(serverClassLoader, service, userType, baseServletType, prefix);
if (servlet == null) return; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null
String prefix2 = prefix;
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) prefix2 = "";
resourceFactory.inject(servlet, NodeHttpServer.this);
//if (finest) logger.finest(threadName + " Create RestServlet(resource.name='" + name + "') = " + servlet);
if (ss != null) {
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
for (int i = 0; i < mappings.length; i++) {
mappings[i] = prefix2 + mappings[i];
}
synchronized (ss) {
ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName() + "(rest.name='" + name + "')", mappings));
}
}
} finally {
scdl.countDown();
}
});
scdl.await();
}
if (webSocketFilter != null) { //加载RestWebSocket
final Set<String> includeValues = new HashSet<>();
@@ -298,7 +328,7 @@ public class NodeHttpServer extends NodeServer {
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) prefix2 = "";
resourceFactory.inject(servlet, NodeHttpServer.this);
if (finest) logger.finest(threadName + " " + stype.getName() + " create RestWebSocketServlet " + servlet);
if (finest) logger.finest(threadName + " " + stype.getName() + " create a RestWebSocketServlet");
if (ss != null) {
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
for (int i = 0; i < mappings.length; i++) {
@@ -310,7 +340,7 @@ public class NodeHttpServer extends NodeServer {
}
//输出信息
if (ss != null && !ss.isEmpty() && sb != null) {
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
ss.sort((AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
int max = 0;
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
if (as.getKey().length() > max) max = as.getKey().length();
@@ -322,6 +352,7 @@ public class NodeHttpServer extends NodeServer {
}
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
}
sb.append(threadName).append(" All HttpServlets load cost " + (System.currentTimeMillis() - starts) + " ms" + LINE_SEPARATOR);
}
}
}

View File

@@ -12,16 +12,17 @@ import java.lang.reflect.*;
import java.net.*;
import java.nio.file.*;
import java.util.*;
import java.util.AbstractMap.SimpleEntry;
import java.util.concurrent.*;
import java.util.function.*;
import java.util.logging.*;
import javax.annotation.Resource;
import javax.annotation.*;
import javax.persistence.Transient;
import static org.redkale.boot.Application.*;
import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.net.Filter;
import org.redkale.net.*;
import org.redkale.net.http.WebSocketServlet;
import org.redkale.net.http.*;
import org.redkale.net.sncp.*;
import org.redkale.service.*;
import org.redkale.source.*;
@@ -89,12 +90,13 @@ public abstract class NodeServer {
public NodeServer(Application application, Server server) {
this.application = application;
this.resourceFactory = application.getResourceFactory().createChild();
this.server = server;
this.resourceFactory = server.getResourceFactory();
this.logger = Logger.getLogger(this.getClass().getSimpleName());
this.serverClassLoader = new RedkaleClassLoader(application.getServerClassLoader());
Thread.currentThread().setContextClassLoader(this.serverClassLoader);
this.serverThread = Thread.currentThread();
this.server.setServerClassLoader(serverClassLoader);
}
public static <T extends NodeServer> NodeServer create(Class<T> clazz, Application application, AnyValue serconf) {
@@ -108,9 +110,9 @@ public abstract class NodeServer {
public void init(AnyValue config) throws Exception {
this.serverConf = config == null ? AnyValue.create() : config;
if (isSNCP()) { // SNCP协议
String host = this.serverConf.getValue("host", "0.0.0.0").replace("0.0.0.0", "");
String host = this.serverConf.getValue("host", isWATCH() ? "127.0.0.1" : "0.0.0.0").replace("0.0.0.0", "");
this.sncpAddress = new InetSocketAddress(host.isEmpty() ? application.localAddress.getHostAddress() : host, this.serverConf.getIntValue("port"));
this.sncpGroup = application.transportFactory.findGroupName(this.sncpAddress);
this.sncpGroup = application.sncpTransportFactory.findGroupName(this.sncpAddress);
//单向SNCP服务不需要对等group
//if (this.sncpGroup == null) throw new RuntimeException("Server (" + String.valueOf(config).replaceAll("\\s+", " ") + ") not found <group> info");
}
@@ -134,20 +136,38 @@ public abstract class NodeServer {
resourceFactory.register(Server.RESNAME_SERVER_ROOT, Path.class, myroot.toPath());
//加入指定的classpath
Server.loadLib(serverClassLoader, logger, this.serverConf.getValue("lib", "${APP_HOME}/libs/*").replace("${APP_HOME}", application.getHome().getPath().replace('\\', '/')));
Server.loadLib(serverClassLoader, logger, this.serverConf.getValue("lib", ""));
this.serverThread.setContextClassLoader(this.serverClassLoader);
}
//必须要进行初始化, 构建Service时需要使用Context中的ExecutorService
server.init(this.serverConf);
//init之后才有Executor
resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, Executor.class, server.getExecutor());
resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, ExecutorService.class, server.getExecutor());
resourceFactory.register(Server.RESNAME_SERVER_EXECUTOR, ThreadPoolExecutor.class, server.getExecutor());
initResource(); //给 DataSource、CacheSource 注册依赖注入时的监听回调事件。
String interceptorClass = this.serverConf.getValue("interceptor", "");
if (!interceptorClass.isEmpty()) {
Class clazz = serverClassLoader.loadClass(interceptorClass);
this.interceptor = (NodeInterceptor) clazz.newInstance();
this.interceptor = (NodeInterceptor) clazz.getDeclaredConstructor().newInstance();
}
ClassFilter<Service> serviceFilter = createServiceClassFilter();
if (application.singletonrun) { //singleton模式下只加载指定的Service
final String ssc = System.getProperty("red" + "kale-singleton-serviceclass");
final String extssc = System.getProperty("red" + "kale-singleton-extserviceclasses");
if (ssc != null) {
final List<String> sscList = new ArrayList<>();
sscList.add(ssc);
if (extssc != null && !extssc.isEmpty()) {
for (String s : extssc.split(",")) {
if (!s.isEmpty()) sscList.add(s);
}
}
serviceFilter.setExpectPredicate(c -> !sscList.contains(c));
}
}
ClassFilter<Filter> filterFilter = createFilterClassFilter();
ClassFilter<Servlet> servletFilter = createServletClassFilter();
ClassFilter otherFilter = createOtherClassFilter();
@@ -156,9 +176,10 @@ public abstract class NodeServer {
long e = System.currentTimeMillis() - s;
logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms");
loadService(serviceFilter, otherFilter); //必须在servlet之前
loadFilter(filterFilter, otherFilter);
loadServlet(servletFilter, otherFilter);
if (!application.singletonrun) { //非singleton模式下才加载Filter、Servlet
loadFilter(filterFilter, otherFilter);
loadServlet(servletFilter, otherFilter);
}
if (this.interceptor != null) this.resourceFactory.inject(this.interceptor);
}
@@ -170,20 +191,29 @@ public abstract class NodeServer {
final NodeServer self = this;
//---------------------------------------------------------------------------------------------
final ResourceFactory appResFactory = application.getResourceFactory();
final TransportFactory appTranFactory = application.getTransportFactory();
final TransportFactory appSncpTranFactory = application.getSncpTransportFactory();
final AnyValue resources = application.config.getAnyValue("resources");
final Map<String, AnyValue> cacheResource = new HashMap<>();
final Map<String, AnyValue> dataResources = new HashMap<>();
final Map<String, SimpleEntry<Class, AnyValue>> cacheResource = new HashMap<>();
final Map<String, SimpleEntry<Class, AnyValue>> dataResources = new HashMap<>();
if (resources != null) {
for (AnyValue sourceConf : resources.getAnyValues("source")) {
try {
Class type = serverClassLoader.loadClass(sourceConf.getValue("value"));
if (type == DataSource.class) {
type = DataMemorySource.class;
for (AnyValue itemConf : sourceConf.getAnyValues("property")) {
if (itemConf.getValue("name", "").contains(DataSources.JDBC_URL)) {
type = DataJdbcSource.class;
break;
}
}
}
if (!Service.class.isAssignableFrom(type)) {
logger.log(Level.SEVERE, "load application source resource, but not Service error: " + sourceConf);
} else if (CacheSource.class.isAssignableFrom(type)) {
cacheResource.put(sourceConf.getValue("name", ""), sourceConf);
cacheResource.put(sourceConf.getValue("name", ""), new SimpleEntry(type, sourceConf));
} else if (DataSource.class.isAssignableFrom(type)) {
dataResources.put(sourceConf.getValue("name", ""), sourceConf);
dataResources.put(sourceConf.getValue("name", ""), new SimpleEntry(type, sourceConf));
} else {
logger.log(Level.SEVERE, "load application source resource, but not CacheSource error: " + sourceConf);
}
@@ -192,7 +222,7 @@ public abstract class NodeServer {
}
}
}
//------------------------------------- 注册Resource --------------------------------------------------------
//------------------------------------- 注册 Resource --------------------------------------------------------
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> {
try {
Resource res = field.getAnnotation(Resource.class);
@@ -215,12 +245,42 @@ public abstract class NodeServer {
}
}, AnyValue.class, AnyValue[].class);
//------------------------------------- 注册DataSource --------------------------------------------------------
//------------------------------------- 注册 DataSource --------------------------------------------------------
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> {
try {
if (field.getAnnotation(Resource.class) == null) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource
DataSource source = DataSources.createDataSource(resourceName);
SimpleEntry<Class, AnyValue> resEntry = dataResources.get(resourceName);
AnyValue sourceConf = resEntry == null ? null : resEntry.getValue();
DataSource source = null;
boolean needinit = true;
if (sourceConf != null) {
final Class sourceType = resEntry.getKey();
if (sourceType == DataJdbcSource.class) {
source = DataSources.createDataSource(resourceName, sourceConf);
} else {
boolean can = false;
for (Constructor cr : sourceType.getConstructors()) {
if (cr.getParameterCount() == 0) {
can = true;
break;
}
}
if (DataSource.class.isAssignableFrom(sourceType) && can) { // 必须有空构造函数
final Service srcService = (Service) src;
SncpClient client = Sncp.getSncpClient(srcService);
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
final Set<String> groups = new HashSet<>();
if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
source = (DataSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
}
}
}
if (source == null) {
source = DataSources.createDataSource(resourceName); //从persistence.xml配置中创建
needinit = false;
}
application.dataSources.add(source);
appResFactory.register(resourceName, DataSource.class, source);
@@ -231,7 +291,7 @@ public abstract class NodeServer {
final Set<String> groups = new HashSet<>();
if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
Service cacheListenerService = Sncp.createLocalService(serverClassLoader, resourceName, DataCacheListenerService.class, appResFactory, appTranFactory, sncpAddr, groups, Sncp.getConf((Service) src));
Service cacheListenerService = Sncp.createLocalService(serverClassLoader, resourceName, DataCacheListenerService.class, appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf((Service) src));
appResFactory.register(resourceName, DataCacheListener.class, cacheListenerService);
localServices.add(cacheListenerService);
sncpServer.consumerAccept(cacheListenerService);
@@ -241,17 +301,19 @@ public abstract class NodeServer {
field.set(src, source);
rf.inject(source, self); // 给其可能包含@Resource的字段赋值;
//NodeServer.this.watchFactory.inject(src);
if (source instanceof Service) ((Service) source).init(null);
if (source instanceof Service && needinit) ((Service) source).init(sourceConf);
} catch (Exception e) {
logger.log(Level.SEVERE, "DataSource inject error", e);
}
}, DataSource.class);
//------------------------------------- 注册CacheSource --------------------------------------------------------
//------------------------------------- 注册 CacheSource --------------------------------------------------------
resourceFactory.register(new ResourceFactory.ResourceLoader() {
@Override
public void load(ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) {
try {
if (field.getAnnotation(Resource.class) == null) return;
if (!(src instanceof Service)) throw new RuntimeException("CacheSource must be inject in Service, cannot " + src);
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不需要注入 CacheSource
final Service srcService = (Service) src;
SncpClient client = Sncp.getSncpClient(srcService);
@@ -260,23 +322,23 @@ public abstract class NodeServer {
if (client != null && client.getSameGroup() != null) groups.add(client.getSameGroup());
if (client != null && client.getDiffGroups() != null) groups.addAll(client.getDiffGroups());
AnyValue sourceConf = cacheResource.get(resourceName);
if (sourceConf == null) sourceConf = dataResources.get(resourceName);
SimpleEntry<Class, AnyValue> resEntry = cacheResource.get(resourceName);
AnyValue sourceConf = resEntry == null ? null : resEntry.getValue();
if (sourceConf == null) {
SimpleEntry<Class, AnyValue> resEntry2 = dataResources.get(resourceName);
sourceConf = resEntry2 == null ? null : resEntry2.getValue();
}
final Class sourceType = sourceConf == null ? CacheMemorySource.class : serverClassLoader.loadClass(sourceConf.getValue("value"));
Object source;
if (DataSource.class.isAssignableFrom(sourceType)) { // DataSource
source = (DataSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, appResFactory, appTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
application.dataSources.add((DataSource) source);
appResFactory.register(resourceName, DataSource.class, source);
} else { // CacheSource
source = (CacheSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, appResFactory, appTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
Object source = null;
if (CacheSource.class.isAssignableFrom(sourceType)) { // CacheSource
source = (CacheSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
Type genericType = field.getGenericType();
ParameterizedType pt = (genericType instanceof ParameterizedType) ? (ParameterizedType) genericType : null;
Type valType = pt == null ? null : pt.getActualTypeArguments()[1];
if (sourceType == CacheMemorySource.class) {
CacheMemorySource memorySource = (CacheMemorySource) source;
memorySource.setStoreType(pt == null ? Serializable.class : (Class) pt.getActualTypeArguments()[0], valType instanceof Class ? (Class) valType : Object.class);
if (field.getAnnotation(Transient.class) != null) memorySource.setNeedStore(false); //必须在setStoreType之后
Type valType = pt == null ? null : pt.getActualTypeArguments()[0];
if (CacheSource.class.isAssignableFrom(sourceType)) {
CacheSource cacheSource = (CacheSource) source;
cacheSource.initValueType(valType instanceof Class ? (Class) valType : Object.class);
cacheSource.initTransient(field.getAnnotation(Transient.class) != null); //必须在initValueType之后
}
application.cacheSources.add((CacheSource) source);
appResFactory.register(resourceName, genericType, source);
@@ -297,20 +359,57 @@ public abstract class NodeServer {
}
}
@Override
public boolean autoNone() {
return false;
}
}, CacheSource.class);
//------------------------------------- 注册 WebSocketNode --------------------------------------------------------
resourceFactory.register(new ResourceFactory.ResourceLoader() {
@Override
public void load(ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) {
try {
if (field.getAnnotation(Resource.class) == null) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不需要注入 WebSocketNode
Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
if (nodeService == null) {
final HashSet<String> groups = new HashSet<>();
if (groups.isEmpty() && isSNCP() && NodeServer.this.sncpGroup != null) groups.add(NodeServer.this.sncpGroup);
nodeService = Sncp.createLocalService(serverClassLoader, resourceName, WebSocketNodeService.class, application.getResourceFactory(), application.getSncpTransportFactory(), NodeServer.this.sncpAddress, groups, (AnyValue) null);
(isSNCP() ? appResFactory : resourceFactory).register(resourceName, WebSocketNode.class, nodeService);
}
resourceFactory.inject(nodeService, self);
field.set(src, nodeService);
if (Sncp.isRemote(nodeService)) {
remoteServices.add(nodeService);
} else {
if (field != null) rf.inject(nodeService); //动态加载的Service也存在按需加载的注入资源
localServices.add(nodeService);
interceptorServices.add(nodeService);
if (consumer != null) consumer.accept(nodeService);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "WebSocketNode inject error", e);
}
}
@Override
public boolean autoNone() {
return false;
}
}, WebSocketNode.class);
}
@SuppressWarnings("unchecked")
protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception {
if (serviceFilter == null) return;
final long starts = System.currentTimeMillis();
final String threadName = "[" + Thread.currentThread().getName() + "] ";
final Set<FilterEntry<? extends Service>> entrys = (Set) serviceFilter.getAllFilterEntrys();
ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory;
final ResourceFactory appResourceFactory = application.getResourceFactory();
final TransportFactory appTransportFactory = application.getTransportFactory();
final TransportFactory appSncpTransFactory = application.getSncpTransportFactory();
for (FilterEntry<? extends Service> entry : entrys) { //service实现类
final Class<? extends Service> serviceImplClass = entry.getType();
if (Modifier.isFinal(serviceImplClass.getModifiers())) continue; //修饰final的类跳过
@@ -320,7 +419,6 @@ public abstract class NodeServer {
if (DataSource.class.isAssignableFrom(serviceImplClass)) continue;
if (CacheSource.class.isAssignableFrom(serviceImplClass)) continue;
if (DataCacheListener.class.isAssignableFrom(serviceImplClass)) continue;
//if (WebSocketNode.class.isAssignableFrom(serviceImplClass)) continue;
}
if (entry.getName().contains("$")) throw new RuntimeException("<name> value cannot contains '$' in " + entry.getProperty());
Service oldother = resourceFactory.find(entry.getName(), serviceImplClass);
@@ -338,15 +436,18 @@ public abstract class NodeServer {
if (localed && (serviceImplClass.isInterface() || Modifier.isAbstract(serviceImplClass.getModifiers()))) continue; //本地模式不能实例化接口和抽象类的Service类
final ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> {
try {
if (SncpClient.parseMethod(serviceImplClass).isEmpty() && serviceImplClass.getAnnotation(Priority.class) == null) { //class没有可用的方法且没有标记启动优先级的 通常为BaseService
if (!serviceImplClass.getName().startsWith("org.redkale.")) logger.log(Level.FINE, serviceImplClass + " cannot load because not found less one public non-final method");
return;
}
Service service;
boolean ws = src instanceof WebSocketServlet;
if (ws || localed) { //本地模式
service = Sncp.createLocalService(serverClassLoader, resourceName, serviceImplClass, appResourceFactory, appTransportFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
service = Sncp.createLocalService(serverClassLoader, resourceName, serviceImplClass, appResourceFactory, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
} else {
service = Sncp.createRemoteService(serverClassLoader, resourceName, serviceImplClass, appTransportFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
service = Sncp.createRemoteService(serverClassLoader, resourceName, serviceImplClass, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
}
if (SncpClient.parseMethod(serviceImplClass).isEmpty()) return; //class没有可用的方法 通常为BaseService
final Class restype = Sncp.getResourceType(service);
if (rf.find(resourceName, restype) == null) {
regFactory.register(resourceName, restype, service);
@@ -397,33 +498,32 @@ public abstract class NodeServer {
}
//----------------- init -----------------
List<Service> swlist = new ArrayList<>(localServices);
Collections.sort(swlist, (o1, o2) -> {
swlist.sort((o1, o2) -> {
Priority p1 = o1.getClass().getAnnotation(Priority.class);
Priority p2 = o2.getClass().getAnnotation(Priority.class);
int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
if (v != 0) return v;
int rs = Sncp.getResourceType(o1).getName().compareTo(Sncp.getResourceType(o2).getName());
if (rs == 0) rs = Sncp.getResourceName(o1).compareTo(Sncp.getResourceName(o2));
return rs;
});
localServices.clear();
localServices.addAll(swlist);
//this.loadPersistData();
final List<String> slist = sb == null ? null : new CopyOnWriteArrayList<>();
CountDownLatch clds = new CountDownLatch(localServices.size());
localServices.parallelStream().forEach(y -> {
try {
long s = System.currentTimeMillis();
y.init(Sncp.getConf(y));
long e = System.currentTimeMillis() - s;
String serstr = Sncp.toSimpleString(y, maxNameLength, maxClassNameLength);
if (slist != null) slist.add(new StringBuilder().append(threadName).append(serstr).append(" load and init in ").append(e).append(" ms").append(LINE_SEPARATOR).toString());
} finally {
clds.countDown();
}
localServices.stream().forEach(y -> {
long s = System.currentTimeMillis();
y.init(Sncp.getConf(y));
long e = System.currentTimeMillis() - s;
String serstr = Sncp.toSimpleString(y, maxNameLength, maxClassNameLength);
if (slist != null) slist.add(new StringBuilder().append(threadName).append(serstr).append(" load and init in ").append(e).append(" ms").append(LINE_SEPARATOR).toString());
});
clds.await();
if (slist != null && sb != null) {
List<String> wlist = new ArrayList<>(slist); //直接使用CopyOnWriteArrayList偶尔会出现莫名的异常(CopyOnWriteArrayList源码1185行)
Collections.sort(wlist);
for (String s : wlist) {
sb.append(s);
}
sb.append(threadName).append("All Services load cost " + (System.currentTimeMillis() - starts) + " ms" + LINE_SEPARATOR);
}
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
}
@@ -565,9 +665,12 @@ public abstract class NodeServer {
public void shutdown() throws IOException {
if (interceptor != null) interceptor.preShutdown(this);
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
final boolean finest = logger.isLoggable(Level.FINEST);
localServices.forEach(y -> {
long s = System.currentTimeMillis();
if (finest) logger.finest(y + " is destroying");
y.destroy(Sncp.getConf(y));
if (finest) logger.finest(y + " was destroyed");
long e = System.currentTimeMillis() - s;
if (e > 2 && sb != null) {
sb.append(Sncp.toSimpleString(y, maxNameLength, maxClassNameLength)).append(" destroy ").append(e).append("ms").append(LINE_SEPARATOR);

View File

@@ -32,7 +32,7 @@ public class NodeSncpServer extends NodeServer {
private NodeSncpServer(Application application, AnyValue serconf) {
super(application, createServer(application, serconf));
this.sncpServer = (SncpServer) this.server;
this.consumer = sncpServer == null ? null : x -> sncpServer.addSncpServlet(x);
this.consumer = sncpServer == null || application.singletonrun ? null : x -> sncpServer.addSncpServlet(x); //singleton模式下不生成SncpServlet
}
public static NodeServer createNodeServer(Application application, AnyValue serconf) {
@@ -44,7 +44,7 @@ public class NodeSncpServer extends NodeServer {
}
private static Server createServer(Application application, AnyValue serconf) {
return new SncpServer(application.getStartTime());
return new SncpServer(application.getStartTime(), application.getResourceFactory().createChild());
}
@Override
@@ -85,6 +85,7 @@ public class NodeSncpServer extends NodeServer {
if (sncpServer != null) loadSncpFilter(this.serverConf.getAnyValue("fliters"), filterFilter);
}
@SuppressWarnings("unchecked")
protected void loadSncpFilter(final AnyValue servletsConf, final ClassFilter<? extends Filter> classFilter) throws Exception {
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
final String threadName = "[" + Thread.currentThread().getName() + "] ";
@@ -92,7 +93,7 @@ public class NodeSncpServer extends NodeServer {
for (FilterEntry<? extends Filter> en : list) {
Class<SncpFilter> clazz = (Class<SncpFilter>) en.getType();
if (Modifier.isAbstract(clazz.getModifiers())) continue;
final SncpFilter filter = clazz.newInstance();
final SncpFilter filter = clazz.getDeclaredConstructor().newInstance();
resourceFactory.inject(filter, this);
DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty();
this.sncpServer.addSncpFilter(filter, filterConf);
@@ -106,6 +107,7 @@ public class NodeSncpServer extends NodeServer {
}
@Override
@SuppressWarnings("unchecked")
protected ClassFilter<Filter> createFilterClassFilter() {
return createClassFilter(null, null, SncpFilter.class, new Class[]{org.redkale.watch.WatchFilter.class}, null, "filters", "filter");
}

View File

@@ -24,16 +24,19 @@ public class NodeWatchServer extends NodeHttpServer {
}
@Override
@SuppressWarnings("unchecked")
protected ClassFilter<Service> createServiceClassFilter() {
return createClassFilter(this.sncpGroup, null, WatchService.class, null, Annotation.class, "services", "service");
}
@Override
@SuppressWarnings("unchecked")
protected ClassFilter<Filter> createFilterClassFilter() {
return createClassFilter(null, null, WatchFilter.class, null, null, "filters", "filter");
}
@Override
@SuppressWarnings("unchecked")
protected ClassFilter<Servlet> createServletClassFilter() {
return createClassFilter(null, WebServlet.class, WatchServlet.class, null, null, "servlets", "servlet");
}

View File

@@ -41,7 +41,7 @@
html.push(' <tr>');
html.push('<td style="color:#ff00ff;">' + action.url + '</td>');
html.push('<td>' + action.comment + '</td>');
html.push('<td class="s">模块ID: ' + servlet.moduleid + '<br/>操作ID: ' + action.actionid + '<br/>需鉴权: ' + (action.auth ? '<font style="font-weight:bold;color:green;">true</font>' : '<font color=red>false</font>') + '</td>');
html.push('<td class="s" style="width:80px;">模块ID: ' + servlet.moduleid + '<br/>操作ID: ' + action.actionid + '<br/>需鉴权: ' + (action.auth ? '<font style="font-weight:bold;color:green;">true</font>' : '<font color=red>false</font>') + '</td>');
var paramshtml = [];
paramshtml.push('<table class="subtable">');
for (var p = 0; p < action.params.length; p++) {

View File

@@ -6,6 +6,7 @@
package org.redkale.boot.watch;
import org.redkale.service.AbstractService;
import org.redkale.util.Comment;
import org.redkale.watch.WatchService;
/**
@@ -14,4 +15,9 @@ import org.redkale.watch.WatchService;
*/
public abstract class AbstractWatchService extends AbstractService implements WatchService {
@Comment("缺少参数")
public static final int RET_WATCH_PARAMS_ILLEGAL = 1600_0001;
@Comment("执行异常")
public static final int RET_WATCH_RUN_EXCEPTION = 1600_0002;
}

View File

@@ -33,7 +33,7 @@ public class FilterWatchService extends AbstractWatchService {
public static final int RET_FILTER_JAR_ILLEGAL = 1601_0005;
@Resource
private Application application;
protected Application application;
@RestMapping(name = "addfilter", auth = false, comment = "动态增加Filter")
public RetResult addFilter(@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar,
@@ -47,4 +47,34 @@ public class FilterWatchService extends AbstractWatchService {
}
return RetResult.success();
}
@RestMapping(name = "test1", auth = false, comment = "预留")
public RetResult test1() {
return RetResult.success();
}
@RestMapping(name = "test2", auth = false, comment = "预留")
public RetResult test2() {
return RetResult.success();
}
@RestMapping(name = "test3", auth = false, comment = "预留")
public RetResult test3() {
return RetResult.success();
}
@RestMapping(name = "test4", auth = false, comment = "预留")
public RetResult test4() {
return RetResult.success();
}
@RestMapping(name = "test5", auth = false, comment = "预留")
public RetResult test5() {
return RetResult.success();
}
@RestMapping(name = "test6", auth = false, comment = "预留")
public RetResult test6() {
return RetResult.success();
}
}

View File

@@ -5,7 +5,16 @@
*/
package org.redkale.boot.watch;
import org.redkale.net.http.RestService;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.stream.Stream;
import javax.annotation.Resource;
import org.redkale.boot.*;
import org.redkale.net.Server;
import org.redkale.net.http.*;
import org.redkale.service.RetResult;
import org.redkale.util.Comment;
/**
*
@@ -14,4 +23,83 @@ import org.redkale.net.http.RestService;
@RestService(name = "server", catalog = "watch", repair = false)
public class ServerWatchService extends AbstractWatchService {
@Comment("不存在的Server节点")
public static final int RET_SERVER_NOT_EXISTS = 1602_0001;
@Comment("更改Server监听地址端口失败")
public static final int RET_SERVER_CHANGEPORT_ERROR = 1602_0002;
@Resource
protected Application application;
@RestMapping(name = "info", comment = "单个Server信息查询")
public RetResult info(@RestParam(name = "#port:") final int port) {
Stream<NodeServer> stream = application.getNodeServers().stream();
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == port).findFirst().orElse(null);
if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + port + ") not found");
return new RetResult(formatToMap(node));
}
@RestMapping(name = "infos", comment = "Server信息查询")
public RetResult infos() {
Map<String, Object> rs = new LinkedHashMap<>();
for (NodeServer ns : application.getNodeServers()) {
Server server = ns.getServer();
rs.put("" + server.getSocketAddress().getPort(), formatToMap(ns));
}
return new RetResult(rs);
}
@RestMapping(name = "changeaddress", comment = "更改Server的监听地址和端口")
public RetResult changeAddress(@RestParam(name = "#port:") final int oldport,
@RestParam(name = "#newhost:") final String newhost, @RestParam(name = "#newport:") final int newport) {
if (oldport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `oldport`");
if (newport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `newport`");
Stream<NodeServer> stream = application.getNodeServers().stream();
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == oldport).findFirst().orElse(null);
if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + oldport + ") not found");
final Server server = node.getServer();
InetSocketAddress newAddr = new InetSocketAddress(newhost == null || newhost.isEmpty() ? server.getSocketAddress().getHostString() : newhost, newport);
try {
server.changeAddress(newAddr);
} catch (IOException e) {
e.printStackTrace();
return new RetResult(RET_SERVER_CHANGEPORT_ERROR, "changeaddress error");
}
return RetResult.success();
}
private Map<String, Object> formatToMap(NodeServer node) {
Server server = node.getServer();
Map<String, Object> rs = new LinkedHashMap<>();
String protocol = server.getProtocol();
if (node instanceof NodeSncpServer) {
protocol += "/SNCP";
} else if (node instanceof NodeWatchServer) {
protocol += "/WATCH";
} else if (node instanceof NodeHttpServer) {
protocol += "/HTTP";
} else {
NodeProtocol np = node.getClass().getAnnotation(NodeProtocol.class);
if (np != null && np.value().length > 0) protocol += "/" + np.value()[0];
}
rs.put("name", server.getName());
rs.put("protocol", protocol);
rs.put("address", server.getSocketAddress());
rs.put("threads", server.getThreads());
rs.put("backlog", server.getBacklog());
rs.put("bufferCapacity", server.getBufferCapacity());
rs.put("bufferPoolSize", server.getBufferPoolSize());
rs.put("charset", server.getCharset() == null ? "UTF-8" : server.getCharset().name());
rs.put("maxbody", server.getMaxbody());
rs.put("maxconns", server.getMaxconns());
rs.put("serverStartTime", server.getServerStartTime());
rs.put("responsePoolSize", server.getResponsePoolSize());
rs.put("readTimeoutSeconds", server.getReadTimeoutSeconds());
rs.put("writeTimeoutSeconds", server.getWriteTimeoutSeconds());
rs.put("createConnectionCount", server.getCreateConnectionCount());
rs.put("livingConnectionCount", server.getLivingConnectionCount());
rs.put("closedConnectionCount", server.getClosedConnectionCount());
return rs;
}
}

View File

@@ -5,10 +5,14 @@
*/
package org.redkale.boot.watch;
import java.lang.reflect.*;
import java.util.*;
import javax.annotation.Resource;
import org.redkale.boot.Application;
import org.redkale.net.TransportFactory;
import org.redkale.boot.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.http.*;
import org.redkale.service.RetResult;
import org.redkale.util.*;
/**
* <p>
@@ -19,21 +23,177 @@ import org.redkale.net.http.*;
@RestService(name = "service", catalog = "watch", repair = false)
public class ServiceWatchService extends AbstractWatchService {
@Resource
private Application application;
@Comment("没有找到目标Service")
public static final int RET_SERVICE_DEST_NOT_EXISTS = 1603_0001;
@Resource
private TransportFactory transportFactory;
protected Application application;
// @RestMapping(name = "load", auth = false, comment = "动态增加Service")
// public RetResult loadService(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
// //待开发
// return RetResult.success();
// }
//
// @RestMapping(name = "stop", auth = false, comment = "动态停止Service")
// public RetResult stopService(String name, String type) {
// //待开发
// return RetResult.success();
// }
@RestConvert(type = void.class)
@RestMapping(name = "setfield", auth = false, comment = "设置Service中指定字段的内容")
public RetResult setfield(@RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type,
@RestParam(name = "field", comment = "字段名") String field,
@RestParam(name = "value", comment = "字段值") String value) {
if (name == null) name = "";
if (type == null) type = "";
if (field == null) field = "";
type = type.trim();
field = field.trim();
if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
if (field.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
Object dest = findService(name, type);
Class clazz = dest.getClass();
Throwable t = null;
try {
Field fieldObj = null;
do {
try {
fieldObj = clazz.getDeclaredField(field);
break;
} catch (Exception e) {
if (t == null) t = e;
}
} while ((clazz = clazz.getSuperclass()) != Object.class);
if (fieldObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")");
fieldObj.setAccessible(true);
fieldObj.set(dest, JsonConvert.root().convertFrom(fieldObj.getGenericType(), value));
return RetResult.success();
} catch (Throwable t2) {
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
}
}
@RestConvert(type = void.class)
@RestMapping(name = "getfield", auth = false, comment = "查询Service中指定字段的内容")
public RetResult getfield(@RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type,
@RestParam(name = "field", comment = "字段名") String field) {
if (name == null) name = "";
if (type == null) type = "";
if (field == null) field = "";
type = type.trim();
field = field.trim();
if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
if (field.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
Object dest = findService(name, type);
Class clazz = dest.getClass();
Throwable t = null;
try {
Field fieldObj = null;
do {
try {
fieldObj = clazz.getDeclaredField(field);
break;
} catch (Exception e) {
if (t == null) t = e;
}
} while ((clazz = clazz.getSuperclass()) != Object.class);
if (fieldObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")");
fieldObj.setAccessible(true);
return new RetResult(fieldObj.get(dest));
} catch (Throwable t2) {
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
}
}
@RestConvert(type = void.class)
@RestMapping(name = "runmethod", auth = false, comment = "调用Service中指定方法")
public RetResult runmethod(@RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type,
@RestParam(name = "method", comment = "Service的方法名") String method,
@RestParam(name = "params", comment = "方法的参数值") List<String> params,
@RestParam(name = "paramtypes", comment = "方法的参数数据类型") List<String> paramtypes) {
if (name == null) name = "";
if (type == null) type = "";
if (method == null) method = "";
type = type.trim();
method = method.trim();
if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
if (method.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `method`");
Object dest = findService(name, type);
Class clazz = dest.getClass();
Throwable t = null;
final int paramcount = params == null ? 0 : params.size();
if (paramtypes != null && paramcount != paramtypes.size()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "params.size not equals to paramtypes.size");
try {
Method methodObj = null;
do {
try {
for (Method m : clazz.getDeclaredMethods()) {
if (m.getName().equals(method) && m.getParameterCount() == paramcount) {
boolean flag = true;
if (paramtypes != null) {
Class[] pts = m.getParameterTypes();
for (int i = 0; i < pts.length; i++) {
if (!pts[i].getName().endsWith(paramtypes.get(i))) {
flag = false;
break;
}
}
}
if (flag) {
methodObj = m;
break;
}
}
}
if (methodObj != null) break;
} catch (Exception e) {
if (t == null) t = e;
}
} while ((clazz = clazz.getSuperclass()) != Object.class);
if (methodObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + (t == null ? ("not found method(" + method + ")") : String.valueOf(t)) + ")");
methodObj.setAccessible(true);
if (paramcount < 1) return new RetResult(methodObj.invoke(dest));
Object[] paramObjs = new Object[paramcount];
Type[] pts = methodObj.getGenericParameterTypes();
for (int i = 0; i < paramObjs.length; i++) {
paramObjs[i] = JsonConvert.root().convertFrom(pts[i], params.get(i));
}
return new RetResult(methodObj.invoke(dest, paramObjs));
} catch (Throwable t2) {
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")");
}
}
protected Object findService(String name, String type) {
Object dest = null;
for (NodeServer ns : application.getNodeServers()) {
ResourceFactory resFactory = ns.getResourceFactory();
List list = resFactory.query((n, s) -> name.equals(n) && s != null && s.getClass().getName().endsWith(type));
if (list == null || list.isEmpty()) continue;
dest = list.get(0);
}
if (dest == null) return new RetResult(RET_SERVICE_DEST_NOT_EXISTS, "not found servie (name=" + name + ", type=" + type + ")");
return dest;
}
@RestMapping(name = "load", auth = false, comment = "动态增加Service")
public RetResult loadService(@RestParam(name = "type", comment = "Service的类名") String type,
@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
//待开发
return RetResult.success();
}
@RestMapping(name = "reload", auth = false, comment = "重新加载Service")
public RetResult reloadService(@RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type) {
//待开发
return RetResult.success();
}
@RestMapping(name = "stop", auth = false, comment = "动态停止Service")
public RetResult stopService(@RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type) {
//待开发
return RetResult.success();
}
@RestMapping(name = "find", auth = false, comment = "查找Service")
public RetResult find(@RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type) {
//待开发
return RetResult.success();
}
}

View File

@@ -20,10 +20,10 @@ import org.redkale.net.http.*;
public class ServletWatchService extends AbstractWatchService {
@Resource
private Application application;
protected Application application;
@Resource
private TransportFactory transportFactory;
protected TransportFactory transportFactory;
//
// @RestMapping(name = "load", auth = false, comment = "动态增加Servlet")
// public RetResult loadServlet(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {

View File

@@ -5,22 +5,118 @@
*/
package org.redkale.boot.watch;
import java.io.*;
import java.lang.reflect.Method;
import java.util.*;
import javax.annotation.Resource;
import org.redkale.boot.Application;
import org.redkale.net.TransportFactory;
import org.redkale.net.http.RestService;
import org.redkale.net.http.*;
import org.redkale.service.*;
import org.redkale.source.*;
import org.redkale.util.*;
/**
* WATCH服务, 操作DataSource源
*
* @author zhangjx
*/
@RestService(name = "source", catalog = "watch", repair = false)
public class SourceWatchService extends AbstractWatchService {
@Resource
private Application application;
@Comment("不存在的Source")
public static final int RET_SOURCE_NOT_EXISTS = 1605_0001;
@Comment("Source不支持getReadPoolSource/getWritePoolSource方法")
public static final int RET_SOURCE_CHANGE_METHOD_NOT_EXISTS = 1605_0002;
@Comment("PoolSource调用change方法失败")
public static final int RET_SOURCE_METHOD_INVOKE_NOT_EXISTS = 1605_0003;
@Resource(name = "APP_HOME")
protected File home;
@Resource
private TransportFactory transportFactory;
protected Application application;
@RestMapping(name = "change", auth = false, comment = "动态更改DataSource的配置")
public RetResult addNode(@RestParam(name = "name", comment = "DataSource的标识") final String name,
@RestParam(name = "properties", comment = "配置") Properties properties,
@RestParam(name = "xmlpath", comment = "配置文件路径") String xmlpath) throws IOException {
if (name == null) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param (name)");
if (properties == null && xmlpath != null) {
File f = new File(xmlpath);
if (!f.isFile()) f = new File(home, xmlpath);
if (!f.isFile()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found file (" + xmlpath + ")");
FileInputStream in = new FileInputStream(f);
Map<String, Properties> map = DataSources.loadPersistenceXml(in);
properties = map.get(name);
}
if (properties == null) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param (properties)");
DataSource source = null;
for (DataSource s : application.getDataSources()) {
String resName = ((Resourcable) s).resourceName();
if (resName == null) continue;
if (!resName.equals(name)) continue;
source = s;
break;
}
if (source == null) return new RetResult(RET_SOURCE_NOT_EXISTS, "not found source (name = " + name + ")");
Method readPoolMethod = null;
Method writePoolMethod = null;
Class stype = source.getClass();
do {
for (Method m : stype.getDeclaredMethods()) {
if (!PoolSource.class.isAssignableFrom(m.getReturnType())) continue;
if (m.getParameterCount() != 0) continue;
if (m.getName().equals("getReadPoolSource")) {
readPoolMethod = m;
} else if (m.getName().equals("getWritePoolSource")) {
writePoolMethod = m;
}
}
} while ((stype = stype.getSuperclass()) != Object.class);
if (readPoolMethod == null) return new RetResult(RET_SOURCE_CHANGE_METHOD_NOT_EXISTS, "not found source method(getReadPoolSource)");
if (writePoolMethod == null) return new RetResult(RET_SOURCE_CHANGE_METHOD_NOT_EXISTS, "not found source method(getWritePoolSource)");
readPoolMethod.setAccessible(true);
writePoolMethod.setAccessible(true);
try {
PoolSource readPoolSource = (PoolSource) readPoolMethod.invoke(source);
PoolSource writePoolSource = (PoolSource) writePoolMethod.invoke(source);
readPoolSource.change(properties);
writePoolSource.change(properties);
return RetResult.success();
} catch (Exception e) {
return new RetResult(RET_SOURCE_METHOD_INVOKE_NOT_EXISTS, "poolsource invoke method('change') error");
}
}
@RestMapping(name = "test1", auth = false, comment = "预留")
public RetResult test1() {
return RetResult.success();
}
@RestMapping(name = "test2", auth = false, comment = "预留")
public RetResult test2() {
return RetResult.success();
}
@RestMapping(name = "test3", auth = false, comment = "预留")
public RetResult test3() {
return RetResult.success();
}
@RestMapping(name = "test4", auth = false, comment = "预留")
public RetResult test4() {
return RetResult.success();
}
@RestMapping(name = "test5", auth = false, comment = "预留")
public RetResult test5() {
return RetResult.success();
}
@RestMapping(name = "test6", auth = false, comment = "预留")
public RetResult test6() {
return RetResult.success();
}
}

View File

@@ -36,10 +36,10 @@ public class TransportWatchService extends AbstractWatchService {
public static final int RET_TRANSPORT_ADDR_EXISTS = 1606_0003;
@Resource
private Application application;
protected Application application;
@Resource
private TransportFactory transportFactory;
protected TransportFactory transportFactory;
@RestMapping(name = "listnodes", auth = false, comment = "获取所有Node节点")
public List<TransportGroupInfo> listNodes() {
@@ -135,4 +135,24 @@ public class TransportWatchService extends AbstractWatchService {
}
return RetResult.success();
}
@RestMapping(name = "test1", auth = false, comment = "预留")
public RetResult test1() {
return RetResult.success();
}
@RestMapping(name = "test2", auth = false, comment = "预留")
public RetResult test2() {
return RetResult.success();
}
@RestMapping(name = "test3", auth = false, comment = "预留")
public RetResult test3() {
return RetResult.success();
}
@RestMapping(name = "test4", auth = false, comment = "预留")
public RetResult test4() {
return RetResult.success();
}
}

View File

@@ -0,0 +1,64 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.Type;
import java.util.*;
import org.redkale.util.*;
import org.redkale.convert.Reader.ValueType;
import static org.redkale.convert.Reader.ValueType.MAP;
/**
* 对不明类型的对象进行反序列化。 <br>
* <b>注意: 目前只支持文本格式</b> <br>
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public class AnyDecoder implements Decodeable<Reader, Object> {
private static final Type collectionObjectType = new TypeToken<Collection<Object>>() {
}.getType();
private static final Type mapObjectType = new TypeToken<Map<String, Object>>() {
}.getType();
private static final Creator<ArrayList> collectionCreator = Creator.create(ArrayList.class);
private static final Creator<HashMap> mapCreator = Creator.create(HashMap.class);
protected final Decodeable<Reader, String> stringDecoder;
protected final CollectionDecoder collectionDecoder;
protected final MapDecoder mapDecoder;
public AnyDecoder(final ConvertFactory factory) {
this.stringDecoder = factory.loadDecoder(String.class);
this.collectionDecoder = new CollectionDecoder(factory, collectionObjectType, Object.class, collectionCreator, this);
this.mapDecoder = new MapDecoder(factory, mapObjectType, String.class, Object.class, mapCreator, stringDecoder, this);
}
@Override
public Object convertFrom(Reader in) {
ValueType vt = in.readType();
if (vt == null) return null;
switch (vt) {
case ARRAY:
return this.collectionDecoder.convertFrom(in);
case MAP:
return this.mapDecoder.convertFrom(in);
}
return this.stringDecoder.convertFrom(in);
}
@Override
public Type getType() {
return void.class;
}
}

View File

@@ -6,6 +6,7 @@
package org.redkale.convert;
import java.lang.reflect.Type;
import java.util.concurrent.CompletableFuture;
/**
* 对不明类型的对象进行序列化; BSON序列化时将对象的类名写入WriterJSON则不写入。
@@ -35,6 +36,29 @@ public final class AnyEncoder<T> implements Encodeable<Writer, T> {
}
}
@SuppressWarnings("unchecked")
public void convertMapTo(final Writer out, final Object... values) {
if (values == null) {
out.writeNull();
} else {
int count = values.length - values.length % 2;
if (out.writeMapB(count / 2, (Encodeable) this, (Encodeable) this, values) < 0) {
for (int i = 0; i < count; i += 2) {
if (i > 0) out.writeArrayMark();
this.convertTo(out, (T) values[i]);
out.writeMapMark();
Object val = values[i + 1];
if (val instanceof CompletableFuture) {
this.convertTo(out, (T) ((CompletableFuture) val).join());
} else {
this.convertTo(out, (T) val);
}
}
}
out.writeMapE();
}
}
@Override
public Type getType() {
return Object.class;

View File

@@ -20,19 +20,19 @@ import java.util.*;
* @param <T> 反解析的数组元素类型
*/
@SuppressWarnings("unchecked")
public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
private final Type type;
protected final Type type;
private final Type componentType;
protected final Type componentType;
private final Class componentClass;
protected final Class componentClass;
protected final Decodeable<Reader, T> decoder;
protected final Decodeable<Reader, T> componentDecoder;
private boolean inited = false;
protected volatile boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public ArrayDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -51,7 +51,7 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
this.componentClass = (Class) this.componentType;
}
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
this.componentDecoder = factory.loadDecoder(this.componentType);
} finally {
inited = true;
synchronized (lock) {
@@ -62,9 +62,19 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
@Override
public T[] convertFrom(Reader in) {
final int len = in.readArrayB();
return convertFrom(in, null);
}
public T[] convertFrom(Reader in, DeMember member) {
byte[] typevals = new byte[1];
int len = in.readArrayB(member, typevals, componentDecoder);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (this.decoder == null) {
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, componentDecoder);
len = Reader.SIGN_NOLENGTH;
}
if (this.componentDecoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
@@ -75,11 +85,16 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
}
}
}
final Decodeable<Reader, T> localdecoder = this.decoder;
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
final List<T> result = new ArrayList();
boolean first = true;
if (len == Reader.SIGN_NOLENGTH) {
while (in.hasNext()) {
result.add(localdecoder.convertFrom(in));
int startPosition = in.position();
while (hasNext(in, member, startPosition, contentLength, first)) {
Reader itemReader = getItemReader(in, member, first);
if (itemReader == null) break;
result.add(readMemberValue(itemReader, member, localdecoder, first));
first = false;
}
} else {
for (int i = 0; i < len; i++) {
@@ -91,9 +106,25 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
return result.toArray(rs);
}
protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) {
return in.hasNext(startPosition, contentLength);
}
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
return decoder;
}
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
return in;
}
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
return decoder.convertFrom(in);
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.decoder + "}";
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.componentDecoder + "}";
}
@Override
@@ -101,4 +132,12 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
return type;
}
public Type getComponentType() {
return componentType;
}
public Decodeable<Reader, T> getComponentDecoder() {
return componentDecoder;
}
}

View File

@@ -19,19 +19,19 @@ import java.lang.reflect.*;
* @param <T> 序列化的数组元素类型
*/
@SuppressWarnings("unchecked")
public final class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
private final Type type;
protected final Type type;
private final Type componentType;
protected final Type componentType;
private final Encodeable anyEncoder;
protected final Encodeable anyEncoder;
private final Encodeable<Writer, Object> encoder;
protected final Encodeable<Writer, Object> componentEncoder;
private boolean inited = false;
protected volatile boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public ArrayEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -45,7 +45,7 @@ public final class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
throw new ConvertException("(" + type + ") is not a array type");
}
factory.register(type, this);
this.encoder = factory.loadEncoder(this.componentType);
this.componentEncoder = factory.loadEncoder(this.componentType);
this.anyEncoder = factory.getAnyEncoder();
} finally {
inited = true;
@@ -57,16 +57,20 @@ public final class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
@Override
public void convertTo(Writer out, T[] value) {
convertTo(out, null, value);
}
public void convertTo(Writer out, EnMember member, T[] value) {
if (value == null) {
out.writeNull();
return;
}
if (value.length == 0) {
out.writeArrayB(0);
out.writeArrayB(0, componentEncoder, value);
out.writeArrayE();
return;
}
if (this.encoder == null) {
if (this.componentEncoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
@@ -77,24 +81,38 @@ public final class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
}
}
}
out.writeArrayB(value.length);
final Type comp = this.componentType;
boolean first = true;
for (Object v : value) {
if (!first) out.writeArrayMark();
((v != null && v.getClass() == comp) ? encoder : anyEncoder).convertTo(out, v);
if (first) first = false;
if (out.writeArrayB(value.length, componentEncoder, value) < 0) {
final Type comp = this.componentType;
boolean first = true;
for (Object v : value) {
if (!first) out.writeArrayMark();
writeMemberValue(out, member, ((v != null && (v.getClass() == comp || out.specify() == comp)) ? componentEncoder : anyEncoder), v, first);
if (first) first = false;
}
}
out.writeArrayE();
}
protected void writeMemberValue(Writer out, EnMember member, Encodeable<Writer, Object> encoder, Object value, boolean first) {
encoder.convertTo(out, value);
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", encoder:" + this.encoder + "}";
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", encoder:" + this.componentEncoder + "}";
}
@Override
public Type getType() {
return type;
}
public Type getComponentType() {
return componentType;
}
public Encodeable<Writer, Object> getComponentEncoder() {
return componentEncoder;
}
}

View File

@@ -0,0 +1,36 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.Type;
/**
* 二进制序列化/反序列化操作类
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类
* @param <W> Writer输出的子类
*/
public abstract class BinaryConvert<R extends Reader, W extends Writer> extends Convert<R, W> {
protected BinaryConvert(ConvertFactory<R, W> factory) {
super(factory);
}
@Override
public final boolean isBinary() {
return true;
}
public abstract byte[] convertTo(final Object value);
public abstract byte[] convertTo(final Type type, final Object value);
public abstract byte[] convertMapTo(final Object... values);
}

View File

@@ -8,7 +8,7 @@ package org.redkale.convert;
import org.redkale.util.Creator;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.*;
/**
* Collection的反序列化操作类 <br>
@@ -21,19 +21,19 @@ import java.util.Collection;
* @param <T> 反解析的集合元素类型
*/
@SuppressWarnings("unchecked")
public final class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
private final Type type;
protected final Type type;
private final Type componentType;
protected final Type componentType;
protected Creator<Collection<T>> creator;
protected final Decodeable<Reader, T> decoder;
protected final Decodeable<Reader, T> componentDecoder;
private boolean inited = false;
protected volatile boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public CollectionDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -43,14 +43,14 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
this.componentType = pt.getActualTypeArguments()[0];
this.creator = factory.loadCreator((Class) pt.getRawType());
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
} else if(factory.isReversible()){
this.componentDecoder = factory.loadDecoder(this.componentType);
} else if (factory.isReversible()) {
this.componentType = Object.class;
this.creator = factory.loadCreator(Object.class);
this.creator = factory.loadCreator(type instanceof Class ? (Class) type : Collection.class);
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
this.componentDecoder = factory.loadDecoder(this.componentType);
} else {
throw new ConvertException("collectiondecoder not support the type (" + type + ")");
throw new ConvertException("CollectionDecoder not support the type (" + type + ")");
}
} finally {
inited = true;
@@ -60,11 +60,32 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
}
}
//仅供类似JsonAnyDecoder这种动态创建使用 不得调用 factory.register
public CollectionDecoder(final ConvertFactory factory, Type type, Type componentType,
Creator<Collection<T>> creator, final Decodeable<Reader, T> componentDecoder) {
Objects.requireNonNull(componentDecoder);
this.type = type;
this.componentType = componentType;
this.creator = creator;
this.componentDecoder = componentDecoder;
this.inited = true;
}
@Override
public Collection<T> convertFrom(Reader in) {
final int len = in.readArrayB();
return convertFrom(in, null);
}
public Collection<T> convertFrom(Reader in, DeMember member) {
byte[] typevals = new byte[1];
int len = in.readArrayB(member, typevals, componentDecoder);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (this.decoder == null) {
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, componentDecoder);
len = Reader.SIGN_NOLENGTH;
}
if (this.componentDecoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
@@ -75,11 +96,16 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
}
}
}
final Decodeable<Reader, T> localdecoder = this.decoder;
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
final Collection<T> result = this.creator.create();
boolean first = true;
if (len == Reader.SIGN_NOLENGTH) {
while (in.hasNext()) {
result.add(localdecoder.convertFrom(in));
int startPosition = in.position();
while (hasNext(in, member, startPosition, contentLength, first)) {
Reader itemReader = getItemReader(in, member, first);
if (itemReader == null) break;
result.add(readMemberValue(itemReader, member, localdecoder, first));
first = false;
}
} else {
for (int i = 0; i < len; i++) {
@@ -90,9 +116,33 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
return result;
}
protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) {
return in.hasNext(startPosition, contentLength);
}
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
return decoder;
}
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
return in;
}
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
return decoder.convertFrom(in);
}
@Override
public Type getType() {
return type;
}
public Type getComponentType() {
return componentType;
}
public Decodeable<Reader, T> getComponentDecoder() {
return componentDecoder;
}
}

View File

@@ -19,15 +19,15 @@ import java.util.Collection;
* @param <T> 序列化的集合元素类型
*/
@SuppressWarnings("unchecked")
public final class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
private final Type type;
protected final Type type;
private final Encodeable<Writer, Object> encoder;
protected final Encodeable<Writer, Object> componentEncoder;
private boolean inited = false;
protected volatile boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public CollectionEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -35,12 +35,12 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
if (type instanceof ParameterizedType) {
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
if (t instanceof TypeVariable) {
this.encoder = factory.getAnyEncoder();
this.componentEncoder = factory.getAnyEncoder();
} else {
this.encoder = factory.loadEncoder(t);
this.componentEncoder = factory.loadEncoder(t);
}
} else {
this.encoder = factory.getAnyEncoder();
this.componentEncoder = factory.getAnyEncoder();
}
} finally {
inited = true;
@@ -52,16 +52,20 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
@Override
public void convertTo(Writer out, Collection<T> value) {
convertTo(out, null, value);
}
public void convertTo(Writer out, EnMember member, Collection<T> value) {
if (value == null) {
out.writeNull();
return;
}
if (value.isEmpty()) {
out.writeArrayB(0);
out.writeArrayB(0, componentEncoder, value);
out.writeArrayE();
return;
}
if (this.encoder == null) {
if (this.componentEncoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
@@ -72,18 +76,31 @@ public final class CollectionEncoder<T> implements Encodeable<Writer, Collection
}
}
}
out.writeArrayB(value.size());
boolean first = true;
for (Object v : value) {
if (!first) out.writeArrayMark();
encoder.convertTo(out, v);
if (first) first = false;
if (out.writeArrayB(value.size(), componentEncoder, value) < 0) {
boolean first = true;
for (Object v : value) {
if (!first) out.writeArrayMark();
writeValue(out, member, v);
if (first) first = false;
}
}
out.writeArrayE();
}
protected void writeValue(Writer out, EnMember member, Object value) {
componentEncoder.convertTo(out, value);
}
@Override
public Type getType() {
return type;
}
public Encodeable<Writer, Object> getComponentEncoder() {
return componentEncoder;
}
public Type getComponentType() {
return componentEncoder == null ? null : componentEncoder.getType();
}
}

View File

@@ -7,7 +7,8 @@ package org.redkale.convert;
import java.lang.reflect.Type;
import java.nio.ByteBuffer;
import java.util.function.Supplier;
import java.util.function.*;
import org.redkale.util.Attribute;
/**
* 序列化/反序列化操作类
@@ -31,8 +32,24 @@ public abstract class Convert<R extends Reader, W extends Writer> {
return this.factory;
}
protected <S extends W> S configWrite(S writer) {
return writer;
}
protected <S extends W> S fieldFunc(S writer, BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc) {
writer.objFieldFunc = objFieldFunc;
writer.objExtFunc = objExtFunc;
return writer;
}
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc);
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc);
public abstract boolean isBinary();
public abstract <T> T convertFrom(final Type type, final byte[] bytes);
public abstract <T> T convertFrom(final Type type, final ByteBuffer... buffers);
public abstract <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers);
@@ -40,4 +57,7 @@ public abstract class Convert<R extends Reader, W extends Writer> {
public abstract ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value);
public abstract ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value);
public abstract ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values);
}

View File

@@ -89,4 +89,9 @@ public final class ConvertColumnEntry {
this.index = index;
}
@Override
public String toString() {
return "ConvertColumnEntry{" + "index=" + index + ", name=" + name + ", ignore=" + ignore + ", convertType=" + convertType + '}';
}
}

View File

@@ -0,0 +1,47 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 序列化时永久禁用该字段, 与ConvertColumn.ignore()的区别在于: ConvertDisabled不能通过ConvertEntity来解禁
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface ConvertDisabled {
/**
* 解析/序列化定制化的TYPE
*
* @return JSON or BSON or ALL
*/
ConvertType type() default ConvertType.ALL;
/**
* ConvertDisabled 的多用类
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Inherited
@Documented
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public static @interface ConvertDisableds {
ConvertDisabled[] value();
}
}

View File

@@ -7,15 +7,15 @@ package org.redkale.convert;
import java.io.File;
import java.lang.reflect.*;
import java.math.BigInteger;
import java.math.*;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.CompletionHandler;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.*;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import org.redkale.convert.ext.InetAddressSimpledCoder.InetSocketAddressSimpledCoder;
import java.util.stream.*;
import org.redkale.convert.ext.*;
import org.redkale.util.*;
@@ -45,6 +45,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
private final ConcurrentHashMap<String, Class> entitys = new ConcurrentHashMap();
private final ConcurrentHashMap<Type, Map<String, SimpledCoder<R, W, ?>>> fieldCoders = new ConcurrentHashMap();
private final ConcurrentHashMap<Type, Decodeable<R, ?>> decoders = new ConcurrentHashMap();
private final ConcurrentHashMap<Type, Encodeable<W, ?>> encoders = new ConcurrentHashMap();
@@ -53,6 +55,9 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
private final Set<Class> skipIgnores = new HashSet();
//key:需要屏蔽的字段value排除的字段名
private final ConcurrentHashMap<Class, Set<String>> ignoreAlls = new ConcurrentHashMap();
private boolean skipAllIgnore = false;
protected ConvertFactory(ConvertFactory<R, W> parent, boolean tiny) {
@@ -86,17 +91,22 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
this.register(Number.class, NumberSimpledCoder.instance);
this.register(String.class, StringSimpledCoder.instance);
this.register(StringWrapper.class, StringWrapperSimpledCoder.instance);
this.register(CharSequence.class, CharSequenceSimpledCoder.instance);
this.register(StringBuilder.class, CharSequenceSimpledCoder.StringBuilderSimpledCoder.instance);
this.register(java.util.Date.class, DateSimpledCoder.instance);
this.register(java.time.Duration.class, DurationSimpledCoder.instance);
this.register(AtomicInteger.class, AtomicIntegerSimpledCoder.instance);
this.register(AtomicLong.class, AtomicLongSimpledCoder.instance);
this.register(BigInteger.class, BigIntegerSimpledCoder.instance);
this.register(BigDecimal.class, BigDecimalSimpledCoder.instance);
this.register(InetAddress.class, InetAddressSimpledCoder.instance);
this.register(DLong.class, DLongSimpledCoder.instance);
this.register(Class.class, TypeSimpledCoder.instance);
this.register(InetSocketAddress.class, InetSocketAddressSimpledCoder.instance);
this.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressSimpledCoder.instance);
this.register(Pattern.class, PatternSimpledCoder.instance);
this.register(File.class, FileSimpledCoder.instance);
this.register(CompletionHandler.class, CompletionHandlerSimpledCoder.instance);
this.register(AsyncHandler.class, AsyncHandlerSimpledCoder.instance);
this.register(URL.class, URLSimpledCoder.instance);
this.register(URI.class, URISimpledCoder.instance);
//---------------------------------------------------------
@@ -106,15 +116,18 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
this.register(short[].class, ShortArraySimpledCoder.instance);
this.register(char[].class, CharArraySimpledCoder.instance);
this.register(int[].class, IntArraySimpledCoder.instance);
this.register(IntStream.class, IntArraySimpledCoder.IntStreamSimpledCoder.instance);
this.register(long[].class, LongArraySimpledCoder.instance);
this.register(LongStream.class, LongArraySimpledCoder.LongStreamSimpledCoder.instance);
this.register(float[].class, FloatArraySimpledCoder.instance);
this.register(double[].class, DoubleArraySimpledCoder.instance);
this.register(DoubleStream.class, DoubleArraySimpledCoder.DoubleStreamSimpledCoder.instance);
this.register(String[].class, StringArraySimpledCoder.instance);
//---------------------------------------------------------
this.register(AnyValue.class, Creator.create(AnyValue.DefaultAnyValue.class));
this.register(HttpCookie.class, new Creator<HttpCookie>() {
@Override
@Creator.ConstructorParameters({"name", "value"})
@ConstructorParameters({"name", "value"})
public HttpCookie create(Object... params) {
return new HttpCookie((String) params[0], (String) params[1]);
}
@@ -131,10 +144,56 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
public abstract boolean isReversible(); //是否可逆的
public abstract boolean isFieldSort(); //当ConvertColumn.index相同时是否按字段名称排序
public abstract ConvertFactory createChild();
public abstract ConvertFactory createChild(boolean tiny);
protected SimpledCoder createEnumSimpledCoder(Class enumClass) {
return new EnumSimpledCoder(enumClass);
}
protected ObjectDecoder createObjectDecoder(Type type) {
return new ObjectDecoder(type);
}
protected ObjectEncoder createObjectEncoder(Type type) {
return new ObjectEncoder(type);
}
protected <E> Decodeable<R, E> createMapDecoder(Type type) {
return new MapDecoder(this, type);
}
protected <E> Encodeable<W, E> createMapEncoder(Type type) {
return new MapEncoder(this, type);
}
protected <E> Decodeable<R, E> createArrayDecoder(Type type) {
return new ArrayDecoder(this, type);
}
protected <E> Encodeable<W, E> createArrayEncoder(Type type) {
return new ArrayEncoder(this, type);
}
protected <E> Decodeable<R, E> createCollectionDecoder(Type type) {
return new CollectionDecoder(this, type);
}
protected <E> Encodeable<W, E> createCollectionEncoder(Type type) {
return new CollectionEncoder(this, type);
}
protected <E> Decodeable<R, E> createStreamDecoder(Type type) {
return new StreamDecoder(this, type);
}
protected <E> Encodeable<W, E> createStreamEncoder(Type type) {
return new StreamEncoder(this, type);
}
public Convert getConvert() {
return convert;
}
@@ -144,15 +203,36 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
return this;
}
public ConvertColumnEntry findRef(AccessibleObject element) {
if (element == null) return null;
ConvertColumnEntry en = this.columnEntrys.get(element);
if (en != null) return en;
final ConvertType ct = this.getConvertType();
ConvertColumn[] ccs = element.getAnnotationsByType(ConvertColumn.class);
public boolean isConvertDisabled(AccessibleObject element) {
ConvertDisabled[] ccs = element.getAnnotationsByType(ConvertDisabled.class);
if (ccs.length == 0 && element instanceof Method) {
final Method method = (Method) element;
String fieldName = readGetSetFieldName(method);
if (fieldName != null) {
try {
ccs = method.getDeclaringClass().getDeclaredField(fieldName).getAnnotationsByType(ConvertDisabled.class);
} catch (Exception e) { //说明没有该字段,忽略异常
}
}
}
final ConvertType ct = this.getConvertType();
for (ConvertDisabled ref : ccs) {
if (ref.type().contains(ct)) return true;
}
return false;
}
public ConvertColumnEntry findRef(Class clazz, AccessibleObject element) {
if (element == null) return null;
ConvertColumnEntry en = this.columnEntrys.get(element);
Set<String> onlyColumns = ignoreAlls.get(clazz);
if (en != null && onlyColumns == null) return en;
final ConvertType ct = this.getConvertType();
ConvertColumn[] ccs = element.getAnnotationsByType(ConvertColumn.class);
String fieldName = null;
if (ccs.length == 0 && element instanceof Method) {
final Method method = (Method) element;
fieldName = readGetSetFieldName(method);
if (fieldName != null) {
try {
ccs = method.getDeclaringClass().getDeclaredField(fieldName).getAnnotationsByType(ConvertColumn.class);
@@ -160,14 +240,31 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
}
}
}
if (onlyColumns != null && fieldName == null) {
if (element instanceof Method) {
fieldName = readGetSetFieldName((Method) element);
} else if (element instanceof Field) {
fieldName = ((Field) element).getName();
}
}
if (ccs.length == 0 && onlyColumns != null && fieldName != null) {
if (!onlyColumns.contains(fieldName)) return new ConvertColumnEntry(fieldName, true);
}
for (ConvertColumn ref : ccs) {
if (ref.type().contains(ct)) {
String realName = ref.name().isEmpty() ? fieldName : ref.name();
if (onlyColumns != null && fieldName != null) {
if (!onlyColumns.contains(realName)) return new ConvertColumnEntry(realName, true);
}
ConvertColumnEntry entry = new ConvertColumnEntry(ref);
if (skipAllIgnore) {
entry.setIgnore(false);
return entry;
}
if (skipIgnores.isEmpty()) return entry;
if (skipIgnores.isEmpty()) {
if (onlyColumns != null && realName != null && onlyColumns.contains(realName)) entry.setIgnore(false);
return entry;
}
if (skipIgnores.contains(((Member) element).getDeclaringClass())) entry.setIgnore(false);
return entry;
}
@@ -294,37 +391,75 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
skipIgnores.add(type);
}
/**
* 屏蔽指定类所有字段,仅仅保留指定字段 <br>
* <b>注意: 该配置优先级高于skipAllIgnore和ConvertColumnEntry配置</b>
*
* @param type 指定的类
* @param excludeColumns 需要排除的字段名
*/
public final void registerIgnoreAll(final Class type, String... excludeColumns) {
Set<String> set = ignoreAlls.get(type);
if (set == null) {
ignoreAlls.put(type, new HashSet<>(Arrays.asList(excludeColumns)));
} else {
set.addAll(Arrays.asList(excludeColumns));
}
}
public final void registerIgnoreAll(final Class type, Collection<String> excludeColumns) {
Set<String> set = ignoreAlls.get(type);
if (set == null) {
ignoreAlls.put(type, new HashSet<>(excludeColumns));
} else {
set.addAll(new ArrayList(excludeColumns));
}
}
public final void register(final Class type, boolean ignore, String... columns) {
for (String column : columns) {
register(type, column, new ConvertColumnEntry(column, ignore));
}
}
public final void register(final Class type, boolean ignore, Collection<String> columns) {
for (String column : columns) {
register(type, column, new ConvertColumnEntry(column, ignore));
}
}
public final boolean register(final Class type, String column, String alias) {
return register(type, column, new ConvertColumnEntry(alias));
}
public final boolean register(final Class type, String column, ConvertColumnEntry entry) {
if (type == null || column == null || entry == null) return false;
Field field = null;
try {
final Field field = type.getDeclaredField(column);
String get = "get";
if (field.getType() == boolean.class || field.getType() == Boolean.class) get = "is";
char[] cols = column.toCharArray();
cols[0] = Character.toUpperCase(cols[0]);
String col2 = new String(cols);
try {
register(type.getMethod(get + col2), entry);
} catch (Exception ex) {
}
try {
register(type.getMethod("set" + col2, field.getType()), entry);
} catch (Exception ex) {
}
return register(field, entry);
field = type.getDeclaredField(column);
} catch (Exception e) {
return false;
}
String get = "get";
if (field != null && (field.getType() == boolean.class || field.getType() == Boolean.class)) get = "is";
char[] cols = column.toCharArray();
cols[0] = Character.toUpperCase(cols[0]);
final String bigColumn = new String(cols);
try {
register(type.getMethod(get + bigColumn), entry);
} catch (NoSuchMethodException mex) {
if (get.length() >= 3) { //get
try {
register(type.getMethod("is" + bigColumn), entry);
} catch (Exception ex) {
}
}
} catch (Exception ex) {
}
try {
register(type.getMethod("set" + bigColumn, field.getType()), entry);
} catch (Exception ex) {
}
return field == null ? true : register(field, entry);
}
public final <E> boolean register(final AccessibleObject field, final ConvertColumnEntry entry) {
@@ -372,12 +507,40 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
encoders.put(clazz, coder);
}
public final <E> void register(final Type clazz, final Decodeable<R, E> decoder, final Encodeable<W, E> encoder) {
decoders.put(clazz, decoder);
encoders.put(clazz, encoder);
}
public final <E> void register(final Type clazz, final Decodeable<R, E> decoder) {
decoders.put(clazz, decoder);
}
public final <E> void register(final Type clazz, final Encodeable<W, E> printer) {
encoders.put(clazz, printer);
public final <E> void register(final Type clazz, final Encodeable<W, E> encoder) {
encoders.put(clazz, encoder);
}
//coder = null表示删除该字段的指定SimpledCoder
public final <E> void register(final Class clazz, final String field, final SimpledCoder<R, W, E> coder) {
if (field == null || clazz == null) return;
try {
clazz.getDeclaredField(field);
} catch (Exception e) {
throw new RuntimeException(clazz + " not found field(" + field + ")");
}
if (coder == null) {
Map map = this.fieldCoders.get(clazz);
if (map != null) map.remove(field);
} else {
this.fieldCoders.computeIfAbsent(clazz, c -> new ConcurrentHashMap<>()).put(field, coder);
}
}
public final <E> SimpledCoder<R, W, E> findFieldCoder(final Type clazz, final String field) {
if (field == null) return null;
Map<String, SimpledCoder<R, W, ?>> map = this.fieldCoders.get(clazz);
if (map == null) return parent == null ? null : parent.findFieldCoder(clazz, field);
return (SimpledCoder) map.get(field);
}
public final <E> Decodeable<R, E> findDecoder(final Type type) {
@@ -395,7 +558,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
public final <E> Decodeable<R, E> loadDecoder(final Type type) {
Decodeable<R, E> decoder = findDecoder(type);
if (decoder != null) return decoder;
if (type instanceof GenericArrayType) return new ArrayDecoder(this, type);
if (type instanceof GenericArrayType) return createArrayDecoder(type);
Class clazz;
if (type instanceof ParameterizedType) {
final ParameterizedType pts = (ParameterizedType) type;
@@ -427,8 +590,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
} else {
throw new ConvertException("not support the type (" + type + ")");
}
decoder = findDecoder(clazz);
if (decoder != null) return decoder;
//此处不能再findDecoder否则type与class不一致, 如: RetResult 和 RetResult<Integer>
return createDecoder(type, clazz);
}
@@ -449,20 +611,23 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
Decodeable<R, E> decoder = null;
ObjectDecoder od = null;
if (clazz.isEnum()) {
decoder = new EnumSimpledCoder(clazz);
decoder = createEnumSimpledCoder(clazz);
} else if (clazz.isArray()) {
decoder = new ArrayDecoder(this, type);
decoder = createArrayDecoder(type);
} else if (Collection.class.isAssignableFrom(clazz)) {
decoder = new CollectionDecoder(this, type);
decoder = createCollectionDecoder(type);
} else if (Stream.class.isAssignableFrom(clazz)) {
decoder = new StreamDecoder(this, type);
decoder = createStreamDecoder(type);
} else if (Map.class.isAssignableFrom(clazz)) {
decoder = new MapDecoder(this, type);
decoder = createMapDecoder(type);
} else if (Optional.class == clazz) {
decoder = new OptionalCoder(this, type);
} else if (clazz == Object.class) {
od = new ObjectDecoder(type);
od = createObjectDecoder(type);
decoder = od;
} else if (!clazz.getName().startsWith("java.")
|| java.net.HttpCookie.class == clazz
|| java.util.AbstractMap.SimpleEntry.class == clazz
|| clazz.getName().startsWith("java.awt.geom.Point2D")) {
Decodeable simpleCoder = null;
for (final Method method : clazz.getDeclaredMethods()) {
@@ -479,7 +644,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
}
}
if (simpleCoder == null) {
od = new ObjectDecoder(type);
od = createObjectDecoder(type);
decoder = od;
} else {
decoder = simpleCoder;
@@ -494,7 +659,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
public final <E> Encodeable<W, E> loadEncoder(final Type type) {
Encodeable<W, E> encoder = findEncoder(type);
if (encoder != null) return encoder;
if (type instanceof GenericArrayType) return new ArrayEncoder(this, type);
if (type instanceof GenericArrayType) return createArrayEncoder(type);
Class clazz;
if (type instanceof ParameterizedType) {
final ParameterizedType pts = (ParameterizedType) type;
@@ -512,8 +677,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
} else {
throw new ConvertException("not support the type (" + type + ")");
}
encoder = findEncoder(clazz);
if (encoder != null) return encoder;
//此处不能再findEncoder否则type与class不一致, 如: RetResult 和 RetResult<Integer>
return createEncoder(type, clazz);
}
@@ -534,18 +698,20 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
Encodeable<W, E> encoder = null;
ObjectEncoder oe = null;
if (clazz.isEnum()) {
encoder = new EnumSimpledCoder(clazz);
encoder = createEnumSimpledCoder(clazz);
} else if (clazz.isArray()) {
encoder = new ArrayEncoder(this, type);
encoder = createArrayEncoder(type);
} else if (Collection.class.isAssignableFrom(clazz)) {
encoder = new CollectionEncoder(this, type);
encoder = createCollectionEncoder(type);
} else if (Stream.class.isAssignableFrom(clazz)) {
encoder = new StreamEncoder(this, type);
encoder = createStreamEncoder(type);
} else if (Map.class.isAssignableFrom(clazz)) {
encoder = new MapEncoder(this, type);
encoder = createMapEncoder(type);
} else if (Optional.class == clazz) {
encoder = new OptionalCoder(this, type);
} else if (clazz == Object.class) {
return (Encodeable<W, E>) this.anyEncoder;
} else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz) {
} else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz || java.util.AbstractMap.SimpleEntry.class == clazz) {
Encodeable simpleCoder = null;
for (final Method method : clazz.getDeclaredMethods()) {
if (!Modifier.isStatic(method.getModifiers())) continue;
@@ -561,7 +727,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
}
}
if (simpleCoder == null) {
oe = new ObjectEncoder(type);
oe = createObjectEncoder(type);
encoder = oe;
} else {
encoder = simpleCoder;

View File

@@ -0,0 +1,102 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.io.Serializable;
import java.lang.reflect.Type;
import org.redkale.convert.json.JsonConvert;
/**
* newConvert参数中的Function返回结果的数据类
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public class ConvertField implements Serializable {
protected String name;
protected Type type;
protected int position;
protected Object value;
public ConvertField() {
}
public ConvertField(String name, Object value) {
this.name = name;
this.value = value;
}
public ConvertField(String name, int position, Object value) {
this.name = name;
this.position = position;
this.value = value;
}
public ConvertField(String name, Type type, Object value) {
this.name = name;
this.type = type;
this.value = value;
}
public ConvertField(String name, Type type, int position, Object value) {
this.name = name;
this.type = type;
this.position = position;
this.value = value;
}
public static ConvertField[] ofArray(Object... items) {
int len = items.length / 2;
ConvertField[] rs = new ConvertField[len];
for (int i = 0; i < len; i++) {
rs[i] = new ConvertField(items[i * 2].toString(), items[i * 2 + 1]);
}
return rs;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
@Override
public String toString() {
return JsonConvert.root().convertTo(this);
}
}

View File

@@ -17,6 +17,7 @@ public enum ConvertType {
JSON(1),
BSON(2),
DIY(64),
ALL(127);
private final int value;

View File

@@ -20,10 +20,12 @@ import org.redkale.util.Attribute;
* @param <F> 字段的数据类型
*/
@SuppressWarnings("unchecked")
public final class DeMember<R extends Reader, T, F> implements Comparable<DeMember<R, T, F>> {
public final class DeMember<R extends Reader, T, F> {
protected int index;
protected int position; //从1开始
protected final Attribute<T, F> attribute;
protected Decodeable<R, F> decoder;
@@ -70,15 +72,23 @@ public final class DeMember<R extends Reader, T, F> implements Comparable<DeMemb
return this.attribute;
}
public Decodeable<R, F> getDecoder() {
return decoder;
}
public int getIndex() {
return this.index;
}
@Override
public final int compareTo(DeMember<R, T, F> o) {
public int getPosition() {
return this.position;
}
public int compareTo(boolean fieldSort, DeMember<R, T, F> o) {
if (o == null) return -1;
if (this.index != o.index) return (this.index == 0 ? Integer.MAX_VALUE : this.index) - (o.index == 0 ? Integer.MAX_VALUE : o.index);
return this.attribute.field().compareTo(o.attribute.field());
if (this.index != 0) throw new RuntimeException("fields (" + attribute.field() + ", " + o.attribute.field() + ") have same ConvertColumn.index(" + this.index + ") in " + attribute.declaringClass());
return fieldSort ? this.attribute.field().compareTo(o.attribute.field()) : 0;
}
@Override
@@ -86,7 +96,7 @@ public final class DeMember<R extends Reader, T, F> implements Comparable<DeMemb
if (this == obj) return true;
if (!(obj instanceof DeMember)) return false;
DeMember other = (DeMember) obj;
return compareTo(other) == 0;
return compareTo(true, other) == 0;
}
@Override

View File

@@ -20,7 +20,7 @@ import org.redkale.util.Attribute;
* @param <F> 字段的数据类型
*/
@SuppressWarnings("unchecked")
public final class EnMember<W extends Writer, T, F> implements Comparable<EnMember<W, T, F>> {
public final class EnMember<W extends Writer, T, F> {
final Attribute<T, F> attribute;
@@ -33,6 +33,8 @@ public final class EnMember<W extends Writer, T, F> implements Comparable<EnMemb
protected int index;
protected int position; //从1开始
public EnMember(Attribute<T, F> attribute, Encodeable<W, F> encoder) {
this.attribute = attribute;
this.encoder = encoder;
@@ -63,15 +65,35 @@ public final class EnMember<W extends Writer, T, F> implements Comparable<EnMemb
return attribute.field().equals(name);
}
public Attribute<T, F> getAttribute() {
return attribute;
}
public Encodeable<W, F> getEncoder() {
return encoder;
}
public boolean isStringType() {
return istring;
}
public boolean isBoolType() {
return isbool;
}
public int getIndex() {
return this.index;
}
@Override
public final int compareTo(EnMember<W, T, F> o) {
public int getPosition() {
return this.position;
}
public int compareTo(boolean fieldSort, EnMember<W, T, F> o) {
if (o == null) return -1;
if (this.index != o.index) return (this.index == 0 ? Integer.MAX_VALUE : this.index) - (o.index == 0 ? Integer.MAX_VALUE : o.index);
return this.attribute.field().compareTo(o.attribute.field());
if (this.index != 0) throw new RuntimeException("fields (" + attribute.field() + ", " + o.attribute.field() + ") have same ConvertColumn.index(" + this.index + ") in " + attribute.declaringClass());
return fieldSort ? this.attribute.field().compareTo(o.attribute.field()) : 0;
}
@Override
@@ -79,7 +101,7 @@ public final class EnMember<W extends Writer, T, F> implements Comparable<EnMemb
if (this == obj) return true;
if (!(obj instanceof EnMember)) return false;
EnMember other = (EnMember) obj;
return compareTo(other) == 0;
return compareTo(true, other) == 0;
}
@Override

View File

@@ -8,7 +8,7 @@ package org.redkale.convert;
import org.redkale.util.Creator;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.*;
/**
* Map的反序列化操作类 <br>
@@ -21,13 +21,13 @@ import java.util.Map;
* @param <V> Map value的数据类型
*/
@SuppressWarnings("unchecked")
public final class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
private final Type type;
protected final Type type;
private final Type keyType;
protected final Type keyType;
private final Type valueType;
protected final Type valueType;
protected Creator<Map<K, V>> creator;
@@ -35,14 +35,21 @@ public final class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
protected final Decodeable<Reader, V> valueDecoder;
private boolean inited = false;
protected volatile boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public MapDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
try {
if (type instanceof ParameterizedType) {
if (type == java.util.Properties.class) {
this.keyType = String.class;
this.valueType = String.class;
this.creator = factory.loadCreator(java.util.Properties.class);
factory.register(type, this);
this.keyDecoder = factory.loadDecoder(String.class);
this.valueDecoder = factory.loadDecoder(String.class);
} else if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type;
this.keyType = pt.getActualTypeArguments()[0];
this.valueType = pt.getActualTypeArguments()[1];
@@ -50,6 +57,12 @@ public final class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
factory.register(type, this);
this.keyDecoder = factory.loadDecoder(this.keyType);
this.valueDecoder = factory.loadDecoder(this.valueType);
} else if (factory.isReversible()) {
this.keyType = Object.class;
this.valueType = Object.class;
this.creator = factory.loadCreator((Class) type);
this.keyDecoder = factory.loadDecoder(this.keyType);
this.valueDecoder = factory.loadDecoder(this.valueType);
} else {
throw new ConvertException("mapdecoder not support the type (" + type + ")");
}
@@ -61,8 +74,26 @@ public final class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
}
}
//仅供类似JsonAnyDecoder这种动态创建使用 不得调用 factory.register
public MapDecoder(final ConvertFactory factory, Type type, Type keyType, Type valueType,
Creator<Map<K, V>> creator, final Decodeable<Reader, K> keyDecoder, Decodeable<Reader, V> valueDecoder) {
Objects.requireNonNull(keyDecoder);
Objects.requireNonNull(valueDecoder);
this.type = type;
this.keyType = keyType;
this.valueType = valueType;
this.creator = creator;
this.keyDecoder = keyDecoder;
this.valueDecoder = valueDecoder;
this.inited = true;
}
@Override
public Map<K, V> convertFrom(Reader in) {
return convertFrom(in, null);
}
public Map<K, V> convertFrom(Reader in, DeMember member) {
if (this.keyDecoder == null || this.valueDecoder == null) {
if (!this.inited) {
synchronized (lock) {
@@ -74,31 +105,85 @@ public final class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
}
}
}
final int len = in.readMapB();
byte[] typevals = new byte[2];
int len = in.readMapB(member, typevals, this.keyDecoder, this.valueDecoder);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, null);
len = Reader.SIGN_NOLENGTH;
}
final Map<K, V> result = this.creator.create();
boolean first = true;
Decodeable<Reader, K> kdecoder = getKeyDecoder(this.keyDecoder, typevals);
Decodeable<Reader, V> vdecoder = getValueDecoder(this.valueDecoder, typevals);
if (len == Reader.SIGN_NOLENGTH) {
while (in.hasNext()) {
K key = keyDecoder.convertFrom(in);
in.readBlank();
V value = valueDecoder.convertFrom(in);
int startPosition = in.position();
while (hasNext(in, member, startPosition, contentLength, first)) {
Reader entryReader = getEntryReader(in, member, first);
if (entryReader == null) break;
K key = readKeyMember(entryReader, member, kdecoder, first);
entryReader.readBlank();
V value = readValueMember(entryReader, member, vdecoder, first);
result.put(key, value);
first = false;
}
} else {
for (int i = 0; i < len; i++) {
K key = keyDecoder.convertFrom(in);
K key = readKeyMember(in, member, kdecoder, first);
in.readBlank();
V value = valueDecoder.convertFrom(in);
V value = readValueMember(in, member, vdecoder, first);
result.put(key, value);
first = false;
}
}
in.readMapE();
return result;
}
protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) {
return in.hasNext(startPosition, contentLength);
}
protected Decodeable<Reader, K> getKeyDecoder(Decodeable<Reader, K> decoder, byte[] typevals) {
return decoder;
}
protected Decodeable<Reader, V> getValueDecoder(Decodeable<Reader, V> decoder, byte[] typevals) {
return decoder;
}
protected Reader getEntryReader(Reader in, DeMember member, boolean first) {
return in;
}
protected K readKeyMember(Reader in, DeMember member, Decodeable<Reader, K> decoder, boolean first) {
return decoder.convertFrom(in);
}
protected V readValueMember(Reader in, DeMember member, Decodeable<Reader, V> decoder, boolean first) {
return decoder.convertFrom(in);
}
@Override
public Type getType() {
return this.type;
}
public Type getKeyType() {
return keyType;
}
public Type getValueType() {
return valueType;
}
public Decodeable<Reader, K> getKeyDecoder() {
return keyDecoder;
}
public Decodeable<Reader, V> getValueDecoder() {
return valueDecoder;
}
}

View File

@@ -20,28 +20,28 @@ import java.util.Map;
* @param <V> Map value的数据类型
*/
@SuppressWarnings("unchecked")
public final class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
private final Type type;
protected final Type type;
private final Encodeable<Writer, K> keyencoder;
protected final Encodeable<Writer, K> keyEncoder;
private final Encodeable<Writer, V> valencoder;
protected final Encodeable<Writer, V> valueEncoder;
private boolean inited = false;
protected volatile boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public MapEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
try {
if (type instanceof ParameterizedType) {
final Type[] pt = ((ParameterizedType) type).getActualTypeArguments();
this.keyencoder = factory.loadEncoder(pt[0]);
this.valencoder = factory.loadEncoder(pt[1]);
this.keyEncoder = factory.loadEncoder(pt[0]);
this.valueEncoder = factory.loadEncoder(pt[1]);
} else {
this.keyencoder = factory.getAnyEncoder();
this.valencoder = factory.getAnyEncoder();
this.keyEncoder = factory.getAnyEncoder();
this.valueEncoder = factory.getAnyEncoder();
}
} finally {
inited = true;
@@ -53,13 +53,17 @@ public final class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
@Override
public void convertTo(Writer out, Map<K, V> value) {
convertTo(out, null, value);
}
public void convertTo(Writer out, EnMember member, Map<K, V> value) {
final Map<K, V> values = value;
if (values == null) {
out.writeNull();
return;
}
if (this.keyencoder == null || this.valencoder == null) {
if (this.keyEncoder == null || this.valueEncoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
@@ -70,20 +74,42 @@ public final class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
}
}
}
out.writeMapB(values.size());
boolean first = true;
for (Map.Entry<K, V> en : values.entrySet()) {
if (!first) out.writeArrayMark();
this.keyencoder.convertTo(out, en.getKey());
out.writeMapMark();
this.valencoder.convertTo(out, en.getValue());
if (first) first = false;
if (out.writeMapB(values.size(), (Encodeable) keyEncoder, (Encodeable) valueEncoder, value) < 0) {
boolean first = true;
for (Map.Entry<K, V> en : values.entrySet()) {
if (!first) out.writeArrayMark();
writeMemberValue(out, member, en.getKey(), en.getValue(), first);
if (first) first = false;
}
}
out.writeMapE();
}
protected void writeMemberValue(Writer out, EnMember member, K key, V value, boolean first) {
keyEncoder.convertTo(out, key);
out.writeMapMark();
valueEncoder.convertTo(out, value);
}
@Override
public Type getType() {
return type;
}
public Type getKeyType() {
return keyEncoder == null ? null : keyEncoder.getType();
}
public Type getValueType() {
return valueEncoder == null ? null : valueEncoder.getType();
}
public Encodeable<Writer, K> getKeyEncoder() {
return keyEncoder;
}
public Encodeable<Writer, V> getValueEncoder() {
return valueEncoder;
}
}

View File

@@ -7,9 +7,7 @@ package org.redkale.convert;
import org.redkale.util.Creator;
import java.lang.reflect.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.*;
import org.redkale.util.*;
/**
@@ -23,7 +21,7 @@ import org.redkale.util.*;
* @param <T> 反解析的数据类型
*/
@SuppressWarnings("unchecked")
public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
protected final Type type;
@@ -31,21 +29,29 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
protected Creator<T> creator;
protected DeMember<R, T, ?>[] creatorConstructorMembers;
protected DeMember<R, T, ?>[] creatorConstructorMembers = new DeMember[0];
protected DeMember<R, T, ?>[] members;
protected DeMember[] members;
protected ConvertFactory factory;
private boolean inited = false;
protected volatile boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
protected ObjectDecoder(Type type) {
this.type = ((type instanceof Class) && ((Class) type).isInterface()) ? Object.class : type;
if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type;
this.typeClass = (Class) pt.getRawType();
} else if (type instanceof TypeVariable) {
TypeVariable tv = (TypeVariable) type;
Type[] ts = tv.getBounds();
if (ts.length == 1 && ts[0] instanceof Class) {
this.typeClass = (Class) ts[0];
} else {
throw new ConvertException("[" + type + "] is no a class or ParameterizedType");
}
} else {
this.typeClass = (Class) type;
}
@@ -55,30 +61,47 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
public void init(final ConvertFactory factory) {
this.factory = factory;
try {
if (type == Object.class) return;
if (type == Object.class) {
this.creatorConstructorMembers = null;
return;
}
Class clazz = null;
if (type instanceof ParameterizedType) {
final ParameterizedType pts = (ParameterizedType) type;
clazz = (Class) (pts).getRawType();
} else if (type instanceof TypeVariable) {
TypeVariable tv = (TypeVariable) type;
Type[] ts = tv.getBounds();
if (ts.length == 1 && ts[0] instanceof Class) {
clazz = (Class) ts[0];
} else {
throw new ConvertException("[" + type + "] is no a class or TypeVariable");
}
} else if (!(type instanceof Class)) {
throw new ConvertException("[" + type + "] is no a class");
} else {
clazz = (Class) type;
}
this.creator = factory.loadCreator(clazz);
if (this.creator == null) throw new ConvertException("Cannot create a creator for " + clazz);
final Set<DeMember> list = new HashSet();
if (!clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) {
this.creator = factory.loadCreator(clazz);
if (this.creator == null) throw new ConvertException("Cannot create a creator for " + clazz);
}
final Set<DeMember> list = new LinkedHashSet();
final String[] cps = ObjectEncoder.findConstructorProperties(this.creator);
try {
ConvertColumnEntry ref;
for (final Field field : clazz.getFields()) {
if (Modifier.isStatic(field.getModifiers())) continue;
ref = factory.findRef(field);
if (factory.isConvertDisabled(field)) continue;
ref = factory.findRef(clazz, field);
if (ref != null && ref.ignore()) continue;
Type t = TypeToken.createClassType(field.getGenericType(), this.type);
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), factory.loadDecoder(t));
Decodeable<R, ?> fieldCoder = factory.findFieldCoder(clazz, field.getName());
if (fieldCoder == null) {
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type);
fieldCoder = factory.loadDecoder(t);
}
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), fieldCoder);
if (ref != null) member.index = ref.getIndex();
list.add(member);
}
@@ -89,7 +112,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
if (method.isSynthetic()) continue;
if (method.getName().length() < 4) continue;
if (!method.getName().startsWith("set")) continue;
if (method.getAnnotation(java.beans.Transient.class) != null) continue;
if (factory.isConvertDisabled(method)) continue;
if (method.getParameterTypes().length != 1) continue;
if (method.getReturnType() != void.class) continue;
if (reversible && (cps == null || !ObjectEncoder.contains(cps, ConvertFactory.readGetSetFieldName(method)))) {
@@ -100,10 +123,15 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
continue;
}
}
ref = factory.findRef(method);
ref = factory.findRef(clazz, method);
if (ref != null && ref.ignore()) continue;
Type t = TypeToken.createClassType(method.getGenericParameterTypes()[0], this.type);
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), factory.loadDecoder(t));
Decodeable<R, ?> fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
if (fieldCoder == null) {
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericParameterTypes()[0], this.type), this.type);
fieldCoder = factory.loadDecoder(t);
}
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), fieldCoder);
if (ref != null) member.index = ref.getIndex();
list.add(member);
}
@@ -132,13 +160,26 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
} catch (NoSuchMethodException ex) {
getter = clazz.getMethod("is" + mn);
}
Type t = TypeToken.createClassType(getter.getGenericParameterTypes()[0], this.type);
Type t = TypeToken.createClassType(TypeToken.getGenericType(getter.getGenericParameterTypes()[0], this.type), this.type);
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, getter, null), factory.loadDecoder(t)));
}
}
}
this.members = list.toArray(new DeMember[list.size()]);
Arrays.sort(this.members);
Arrays.sort(this.members, (a, b) -> a.compareTo(factory.isFieldSort(), b));
Set<Integer> pos = new HashSet<>();
for (int i = 0; i < this.members.length; i++) {
if (this.members[i].index > 0) pos.add(this.members[i].index);
}
int pidx = 0;
for (DeMember member : this.members) {
if (member.index > 0) {
member.position = member.index;
} else {
while (pos.contains(++pidx));
member.position = pidx;
}
}
if (cps != null) {
final String[] fields = cps;
@@ -172,7 +213,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
* @return 反解析后的对象结果
*/
@Override
public final T convertFrom(final R in) {
public T convertFrom(final R in) {
final String clazz = in.readObjectB(typeClass);
if (clazz == null) return null;
if (!clazz.isEmpty()) return (T) factory.loadDecoder(factory.getEntityAlias(clazz)).convertFrom(in);
@@ -185,16 +226,23 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
}
}
}
if (this.creator == null) {
if (typeClass.isInterface() || Modifier.isAbstract(typeClass.getModifiers())) {
throw new ConvertException("[" + typeClass + "] is a interface or abstract class, cannot create it's Creator.");
}
}
if (this.creatorConstructorMembers == null) { //空构造函数
final T result = this.creator.create();
while (in.hasNext()) {
final T result = this.creator == null ? null : this.creator.create();
boolean first = true;
while (hasNext(in, first)) {
DeMember member = in.readFieldName(members);
in.readBlank();
if (member == null) {
in.skipValue(); //跳过不存在的属性的值
} else {
member.read(in, result);
readMemberValue(in, member, result, first);
}
first = false;
}
in.readObjectE(typeClass);
return result;
@@ -203,13 +251,14 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
final Object[] constructorParams = new Object[fields.length];
final Object[][] otherParams = new Object[this.members.length][2];
int oc = 0;
while (in.hasNext()) {
boolean first = true;
while (hasNext(in, first)) {
DeMember member = in.readFieldName(members);
in.readBlank();
if (member == null) {
in.skipValue(); //跳过不存在的属性的值
} else {
Object val = member.read(in);
Object val = readMemberValue(in, member, first);
boolean flag = true;
for (int i = 0; i < fields.length; i++) {
if (member == fields[i]) {
@@ -219,9 +268,12 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
}
}
if (flag) otherParams[oc++] = new Object[]{member.attribute, val};
}
first = false;
}
in.readObjectE(typeClass);
if (this.creator == null) return null;
final T result = this.creator.create(constructorParams);
for (int i = 0; i < oc; i++) {
((Attribute) otherParams[i][0]).set(result, otherParams[i][1]);
@@ -230,11 +282,27 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
}
}
protected boolean hasNext(R in, boolean first) {
return in.hasNext();
}
protected Object readMemberValue(R in, DeMember member, boolean first) {
return member.read(in);
}
protected void readMemberValue(R in, DeMember member, T result, boolean first) {
member.read(in, result);
}
@Override
public final Type getType() {
public Type getType() {
return this.type;
}
public DeMember[] getMembers() {
return Arrays.copyOf(members, members.length);
}
@Override
public String toString() {
return "ObjectDecoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}';

View File

@@ -20,7 +20,7 @@ import org.redkale.util.*;
* @param <T> 序列化的数据类型
*/
@SuppressWarnings("unchecked")
public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
static final Type[] TYPEZERO = new Type[0];
@@ -32,15 +32,23 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
protected ConvertFactory factory;
private boolean inited = false;
protected volatile boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
protected ObjectEncoder(Type type) {
this.type = type;
if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type;
this.typeClass = (Class) pt.getRawType();
} else if (type instanceof TypeVariable) {
TypeVariable tv = (TypeVariable) type;
Type[] ts = tv.getBounds();
if (ts.length == 1 && ts[0] instanceof Class) {
this.typeClass = (Class) ts[0];
} else {
throw new ConvertException("[" + type + "] is no a class or ParameterizedType");
}
} else {
this.typeClass = (Class) type;
}
@@ -53,7 +61,7 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
if (type == Object.class) return;
//if (!(type instanceof Class)) throw new ConvertException("[" + type + "] is no a class");
final Class clazz = this.typeClass;
final Set<EnMember> list = new HashSet();
final Set<EnMember> list = new LinkedHashSet();
final boolean reversible = factory.isReversible();
Creator creator = null;
try {
@@ -66,10 +74,15 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
ConvertColumnEntry ref;
for (final Field field : clazz.getFields()) {
if (Modifier.isStatic(field.getModifiers())) continue;
ref = factory.findRef(field);
if (factory.isConvertDisabled(field)) continue;
ref = factory.findRef(clazz, field);
if (ref != null && ref.ignore()) continue;
Type t = TypeToken.createClassType(field.getGenericType(), this.type);
EnMember member = new EnMember(createAttribute(factory, clazz, field, null, null), factory.loadEncoder(t));
Encodeable<W, ?> fieldCoder = factory.findFieldCoder(clazz, field.getName());
if (fieldCoder == null) {
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type);
fieldCoder = factory.loadEncoder(t);
}
EnMember member = new EnMember(createAttribute(factory, clazz, field, null, null), fieldCoder);
if (ref != null) member.index = ref.getIndex();
list.add(member);
}
@@ -80,7 +93,7 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
if (method.getName().length() < 3) continue;
if (method.getName().equals("getClass")) continue;
if (!method.getName().startsWith("is") && !method.getName().startsWith("get")) continue;
if (method.getAnnotation(java.beans.Transient.class) != null) continue;
if (factory.isConvertDisabled(method)) continue;
if (method.getParameterTypes().length != 0) continue;
if (method.getReturnType() == void.class) continue;
if (reversible && (cps == null || !contains(cps, ConvertFactory.readGetSetFieldName(method)))) {
@@ -91,15 +104,32 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
continue;
}
}
ref = factory.findRef(method);
ref = factory.findRef(clazz, method);
if (ref != null && ref.ignore()) continue;
Type t = TypeToken.createClassType(method.getGenericReturnType(), this.type);
EnMember member = new EnMember(createAttribute(factory, clazz, null, method, null), factory.loadEncoder(t));
Encodeable<W, ?> fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
if (fieldCoder == null) {
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericReturnType(), this.type), this.type);
fieldCoder = factory.loadEncoder(t);
}
EnMember member = new EnMember(createAttribute(factory, clazz, null, method, null), fieldCoder);
if (ref != null) member.index = ref.getIndex();
list.add(member);
}
this.members = list.toArray(new EnMember[list.size()]);
Arrays.sort(this.members);
Arrays.sort(this.members, (a, b) -> a.compareTo(factory.isFieldSort(), b));
Set<Integer> pos = new HashSet<>();
for (int i = 0; i < this.members.length; i++) {
if (this.members[i].index > 0) pos.add(this.members[i].index);
}
int pidx = 0;
for (EnMember member : this.members) {
if (member.index > 0) {
member.position = member.index;
} else {
while (pos.contains(++pidx));
member.position = pidx;
}
}
} catch (Exception ex) {
throw new ConvertException(ex);
@@ -113,7 +143,7 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
}
@Override
public final void convertTo(W out, T value) {
public void convertTo(W out, T value) {
if (value == null) {
out.writeObjectNull(null);
return;
@@ -127,24 +157,42 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
}
}
}
if (value.getClass() != this.typeClass) {
if (value.getClass() != this.typeClass && !this.type.equals(out.specify())) {
final Class clz = value.getClass();
if (out.needWriteClassName()) out.writeClassName(factory.getEntityAlias(clz));
factory.loadEncoder(clz).convertTo(out, value);
return;
}
out.writeObjectB(value);
for (EnMember member : members) {
out.writeObjectField(member, value);
if (out.writeObjectB(value) < 0) {
int maxPosition = 0;
for (EnMember member : members) {
maxPosition = member.getPosition();
out.writeObjectField(member, value);
}
if (out.objExtFunc != null) {
ConvertField[] extFields = out.objExtFunc.apply(value);
if (extFields != null) {
Encodeable<W, ?> anyEncoder = factory.getAnyEncoder();
for (ConvertField en : extFields) {
if (en == null) continue;
maxPosition++;
out.writeObjectField(en.getName(), en.getType(), Math.max(en.getPosition(), maxPosition), anyEncoder, en.getValue());
}
}
}
}
out.writeObjectE(value);
}
@Override
public final Type getType() {
public Type getType() {
return this.type;
}
public EnMember[] getMembers() {
return Arrays.copyOf(members, members.length);
}
@Override
public String toString() {
return "ObjectEncoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}';
@@ -206,8 +254,9 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
}
static String[] findConstructorProperties(Creator creator) {
if (creator == null) return null;
try {
Creator.ConstructorParameters cps = creator.getClass().getMethod("create", Object[].class).getAnnotation(Creator.ConstructorParameters.class);
ConstructorParameters cps = creator.getClass().getMethod("create", Object[].class).getAnnotation(ConstructorParameters.class);
return cps == null ? null : cps.value();
} catch (Exception e) {
return null;
@@ -217,24 +266,24 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
static Attribute createAttribute(final ConvertFactory factory, Class clazz, final Field field, final Method getter, final Method setter) {
String fieldalias;
if (field != null) { // public field
ConvertColumnEntry ref = factory.findRef(field);
ConvertColumnEntry ref = factory.findRef(clazz, field);
fieldalias = ref == null || ref.name().isEmpty() ? field.getName() : ref.name();
} else if (getter != null) {
ConvertColumnEntry ref = factory.findRef(getter);
ConvertColumnEntry ref = factory.findRef(clazz, getter);
String mfieldname = ConvertFactory.readGetSetFieldName(getter);
if (ref == null) {
try {
ref = factory.findRef(clazz.getDeclaredField(mfieldname));
ref = factory.findRef(clazz, clazz.getDeclaredField(mfieldname));
} catch (Exception e) {
}
}
fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name();
} else { // setter != null
ConvertColumnEntry ref = factory.findRef(setter);
ConvertColumnEntry ref = factory.findRef(clazz, setter);
String mfieldname = ConvertFactory.readGetSetFieldName(setter);
if (ref == null) {
try {
ref = factory.findRef(clazz.getDeclaredField(mfieldname));
ref = factory.findRef(clazz, clazz.getDeclaredField(mfieldname));
} catch (Exception e) {
}
}

View File

@@ -0,0 +1,108 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.*;
import java.util.*;
/**
* Optional 的SimpledCoder实现
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public class OptionalCoder<R extends Reader, W extends Writer, T> extends SimpledCoder<R, W, Optional<T>> {
private final Type type;
private final Type componentType;
protected final Class componentClass;
protected final Decodeable<Reader, T> decoder;
protected final Encodeable<Writer, T> encoder;
protected volatile boolean inited = false;
private final Object lock = new Object();
@SuppressWarnings("unchecked")
public OptionalCoder(final ConvertFactory factory, final Type type) {
this.type = type;
try {
if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type;
this.componentType = pt.getActualTypeArguments()[0];
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
if (this.componentType instanceof TypeVariable) {
this.encoder = factory.getAnyEncoder();
this.componentClass = Object.class;
} else {
if (componentType instanceof ParameterizedType) {
final ParameterizedType pt2 = (ParameterizedType) componentType;
this.componentClass = (Class) pt2.getRawType();
} else {
this.componentClass = (Class) componentType;
}
this.encoder = factory.loadEncoder(this.componentType);
}
} else {
this.componentType = Object.class;
this.componentClass = Object.class;
this.decoder = factory.loadDecoder(this.componentType);
this.encoder = factory.getAnyEncoder();
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
}
@Override
public void convertTo(W out, Optional<T> value) {
if (value == null || !value.isPresent()) {
out.writeObjectNull(null);
return;
}
if (this.encoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
this.encoder.convertTo(out, value.get());
}
@Override
public Optional<T> convertFrom(R in) {
if (this.decoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return Optional.ofNullable(this.decoder.convertFrom(in));
}
}

View File

@@ -15,6 +15,10 @@ package org.redkale.convert;
*/
public abstract class Reader {
public static enum ValueType {
STRING, ARRAY, MAP;
}
//当前对象字段名的游标
protected int fieldIndex;
@@ -22,12 +26,46 @@ public abstract class Reader {
public static final short SIGN_NOLENGTH = -2;
public static final short SIGN_NOLENBUTBYTES = -3; //目前只适合于protobuf的boolean[]...double[]类型
/**
* 是否还存在下个元素或字段
* 是否还存在下个元素或字段 <br>
* 注意: 主要用于Array、Collection、Stream或Map等集合对象
*
* @param startPosition 起始位置
* @param contentLength 内容大小, 不确定的传-1
*
* @return 是否还存在下个元素或字段
*/
public abstract boolean hasNext();
public abstract boolean hasNext(int startPosition, int contentLength);
/**
* 是否还存在下个元素或字段
*
*
* @return 是否还存在下个元素或字段
*/
public boolean hasNext() {
return hasNext(-1, -1);
}
/**
* 获取当前位置
*
* @return 当前位置
*/
public abstract int position();
/**
* 读取字段值内容的字节数 <br>
* 只有在readXXXB方法返回SIGN_NOLENBUTBYTES值才会调用此方法
*
* @param member DeMember
* @param decoder Decodeable
*
* @return 内容大小, 不确定返回-1
*/
public abstract int readMemberContentLength(DeMember member, Decodeable decoder);
/**
* 跳过值(不包含值前面的字段)
@@ -39,6 +77,13 @@ public abstract class Reader {
*/
public abstract void readBlank();
/**
* 读取下个值的类型
*
* @return ValueType
*/
public abstract ValueType readType();
/**
* 读取对象的类名, 返回 null 表示对象为null 返回空字符串表示当前class与返回的class一致返回非空字符串表示class是当前class的子类。
*
@@ -61,9 +106,13 @@ public abstract class Reader {
/**
* 读取数组的开头并返回数组的长度
*
* @param member DeMember
* @param typevals byte[]
* @param componentDecoder Decodeable
*
* @return 返回数组的长度
*/
public abstract int readArrayB();
public abstract int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder);
/**
* 读取数组的尾端
@@ -74,9 +123,14 @@ public abstract class Reader {
/**
* 读取map的开头并返回map的size
*
* @param member DeMember
* @param typevals byte[]
* @param keyDecoder Decodeable
* @param valueDecoder Decodeable
*
* @return 返回map的size
*/
public abstract int readMapB();
public abstract int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valueDecoder);
/**
* 读取数组的尾端
@@ -107,6 +161,13 @@ public abstract class Reader {
*/
public abstract byte readByte();
/**
* 读取byte[]
*
* @return byte[]
*/
public abstract byte[] readByteArray();
/**
* 读取一个char值
*

View File

@@ -22,7 +22,7 @@ import java.lang.reflect.Type;
*/
public abstract class SimpledCoder<R extends Reader, W extends Writer, T> implements Decodeable<R, T>, Encodeable<W, T> {
private Type type;
protected Type type;
@Override
public abstract void convertTo(final W out, final T value);

View File

@@ -22,19 +22,19 @@ import java.util.stream.Stream;
* @param <T> 反解析的集合元素类型
*/
@SuppressWarnings("unchecked")
public final class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
private final Type type;
protected final Type type;
private final Type componentType;
protected final Type componentType;
protected Creator<Stream<T>> creator;
protected final Decodeable<Reader, T> decoder;
protected final Decodeable<Reader, T> componentDecoder;
private boolean inited = false;
protected volatile boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public StreamDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -44,7 +44,7 @@ public final class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
this.componentType = pt.getActualTypeArguments()[0];
this.creator = factory.loadCreator((Class) pt.getRawType());
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
this.componentDecoder = factory.loadDecoder(this.componentType);
} else {
throw new ConvertException("StreamDecoder not support the type (" + type + ")");
}
@@ -58,9 +58,19 @@ public final class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
@Override
public Stream<T> convertFrom(Reader in) {
final int len = in.readArrayB();
return convertFrom(in, null);
}
public Stream<T> convertFrom(Reader in, DeMember member) {
byte[] typevals = new byte[1];
int len = in.readArrayB(member, typevals, this.componentDecoder);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (this.decoder == null) {
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, this.componentDecoder);
len = Reader.SIGN_NOLENGTH;
}
if (this.componentDecoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
@@ -71,11 +81,16 @@ public final class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
}
}
}
final Decodeable<Reader, T> localdecoder = this.decoder;
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
final List<T> result = new ArrayList();
boolean first = true;
if (len == Reader.SIGN_NOLENGTH) {
while (in.hasNext()) {
result.add(localdecoder.convertFrom(in));
int startPosition = in.position();
while (hasNext(in, member, startPosition, contentLength, first)) {
Reader itemReader = getItemReader(in, member, first);
if (itemReader == null) break;
result.add(readMemberValue(itemReader, member, localdecoder, first));
first = false;
}
} else {
for (int i = 0; i < len; i++) {
@@ -86,9 +101,33 @@ public final class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
return result.stream();
}
protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) {
return in.hasNext(startPosition, contentLength);
}
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
return decoder;
}
protected Reader getItemReader(Reader in, DeMember member, boolean first) {
return in;
}
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
return decoder.convertFrom(in);
}
@Override
public Type getType() {
return type;
}
public Type getComponentType() {
return componentType;
}
public Decodeable<Reader, T> getComponentDecoder() {
return componentDecoder;
}
}

View File

@@ -19,15 +19,15 @@ import java.util.stream.Stream;
* @param <T> 序列化的集合元素类型
*/
@SuppressWarnings("unchecked")
public final class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
public class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
private final Type type;
protected final Type type;
private final Encodeable<Writer, Object> encoder;
protected final Encodeable<Writer, Object> componentEncoder;
private boolean inited = false;
protected volatile boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
public StreamEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -35,12 +35,12 @@ public final class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
if (type instanceof ParameterizedType) {
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
if (t instanceof TypeVariable) {
this.encoder = factory.getAnyEncoder();
this.componentEncoder = factory.getAnyEncoder();
} else {
this.encoder = factory.loadEncoder(t);
this.componentEncoder = factory.loadEncoder(t);
}
} else {
this.encoder = factory.getAnyEncoder();
this.componentEncoder = factory.getAnyEncoder();
}
} finally {
inited = true;
@@ -52,17 +52,21 @@ public final class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
@Override
public void convertTo(Writer out, Stream<T> value) {
convertTo(out, null, value);
}
public void convertTo(Writer out, EnMember member, Stream<T> value) {
if (value == null) {
out.writeNull();
return;
}
Object[] array = value.toArray();
if (array.length == 0) {
out.writeArrayB(0);
out.writeArrayB(0, componentEncoder, array);
out.writeArrayE();
return;
}
if (this.encoder == null) {
if (this.componentEncoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
@@ -73,18 +77,31 @@ public final class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
}
}
}
out.writeArrayB(array.length);
boolean first = true;
for (Object v : array) {
if (!first) out.writeArrayMark();
encoder.convertTo(out, v);
if (first) first = false;
if (out.writeArrayB(array.length, componentEncoder, array) < 0) {
boolean first = true;
for (Object v : array) {
if (!first) out.writeArrayMark();
writeMemberValue(out, member, v, first);
if (first) first = false;
}
}
out.writeArrayE();
}
protected void writeMemberValue(Writer out, EnMember member, Object value, boolean first) {
componentEncoder.convertTo(out, value);
}
@Override
public Type getType() {
return type;
}
public Encodeable<Writer, Object> getComponentEncoder() {
return componentEncoder;
}
public Type getComponentType() {
return componentEncoder == null ? null : componentEncoder.getType();
}
}

View File

@@ -0,0 +1,36 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.Type;
/**
* 文本序列化/反序列化操作类
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类
* @param <W> Writer输出的子类
*/
public abstract class TextConvert<R extends Reader, W extends Writer> extends Convert<R, W> {
protected TextConvert(ConvertFactory<R, W> factory) {
super(factory);
}
@Override
public final boolean isBinary() {
return false;
}
public abstract String convertTo(final Object value);
public abstract String convertTo(final Type type, final Object value);
public abstract String convertMapTo(final Object... values);
}

View File

@@ -5,7 +5,9 @@
*/
package org.redkale.convert;
import org.redkale.util.Attribute;
import java.lang.reflect.*;
import java.util.function.*;
import org.redkale.util.*;
/**
* 序列化的数据输出流
@@ -20,6 +22,44 @@ public abstract class Writer {
//当前对象输出字段名之前是否需要分隔符, JSON字段间的分隔符为,逗号
protected boolean comma;
//convertTo时是否以指定Type的ObjectEncoder进行处理
protected Type specify;
//对某个字段值进行动态处理
protected BiFunction<Attribute, Object, Object> objFieldFunc;
//对某个对象进行动态扩展字段值处理
protected Function<Object, ConvertField[]> objExtFunc;
/**
* 设置specify
*
* @param value Type
*/
public void specify(Type value) {
if (value instanceof GenericArrayType) {
this.specify = ((GenericArrayType) value).getGenericComponentType();
} else if (value instanceof Class && ((Class) value).isArray()) {
this.specify = ((Class) value).getComponentType();
} else {
this.specify = value;
}
}
protected boolean recycle() {
this.objFieldFunc = null;
return true;
}
/**
* 返回specify
*
* @return int
*/
public Type specify() {
return this.specify;
}
/**
* 当tiny=true时 字符串为空、boolean为false的字段值都会被跳过 不会输出。
*
@@ -51,9 +91,12 @@ public abstract class Writer {
* 注: 覆盖此方法必须要先调用父方法 super.writeObjectB(obj);
*
* @param obj 写入的对象
*
* @return 返回-1表示还没有写入对象内容大于-1表示已写入对象内容返回对象内容大小
*/
public void writeObjectB(Object obj) {
public int writeObjectB(Object obj) {
this.comma = false;
return -1;
}
/**
@@ -74,8 +117,13 @@ public abstract class Writer {
* @param obj 写入的对象
*/
@SuppressWarnings("unchecked")
public final void writeObjectField(final EnMember member, Object obj) {
Object value = member.attribute.get(obj);
public void writeObjectField(final EnMember member, Object obj) {
Object value;
if (objFieldFunc == null) {
value = member.attribute.get(obj);
} else {
value = objFieldFunc.apply(member.attribute, obj);
}
if (value == null) return;
if (tiny()) {
if (member.istring) {
@@ -84,11 +132,49 @@ public abstract class Writer {
if (!((Boolean) value)) return;
}
}
this.writeFieldName(member.attribute);
Attribute attr = member.getAttribute();
this.writeFieldName(attr.field(), attr.genericType(), member.getPosition());
member.encoder.convertTo(this, value);
this.comma = true;
}
/**
* 输出一个对象的某个扩展字段
*
*
* @param fieldName 字段名称
* @param fieldType 字段类型
* @param fieldPos 字段顺序
* @param anyEncoder Encoder
* @param value 写入的字段对象
*/
@SuppressWarnings("unchecked")
public void writeObjectField(final String fieldName, Type fieldType, int fieldPos, Encodeable anyEncoder, Object value) {
if (value == null) return;
if (fieldType == null) fieldType = value.getClass();
if (tiny() && fieldType instanceof Class) {
Class clazz = (Class) fieldType;
if (CharSequence.class.isAssignableFrom(clazz)) {
if (((CharSequence) value).length() == 0) return;
} else if (clazz == boolean.class || clazz == Boolean.class) {
if (!((Boolean) value)) return;
}
}
this.writeFieldName(fieldName, fieldType, fieldPos);
anyEncoder.convertTo(this, value);
this.comma = true;
}
/**
* 输出一个字段名
*
* @param member 字段
*/
public final void writeFieldName(final EnMember member) {
Attribute attr = member.getAttribute();
this.writeFieldName(attr.field(), attr.genericType(), member.getPosition());
}
/**
* 输出一个对象后的操作
*
@@ -99,9 +185,13 @@ public abstract class Writer {
/**
* 输出一个数组前的操作
*
* @param size 数组长度
* @param size 数组长度
* @param componentEncoder Encodeable
* @param obj 对象, 不一定是数组、Collection对象也可能是伪Collection对象
*
* @return 返回-1表示还没有写入对象内容大于-1表示已写入对象内容返回对象内容大小
*/
public abstract void writeArrayB(int size);
public abstract int writeArrayB(int size, Encodeable<Writer, Object> componentEncoder, Object obj);
/**
* 输出数组元素间的间隔符
@@ -118,9 +208,14 @@ public abstract class Writer {
/**
* 输出一个Map前的操作
*
* @param size map大小
* @param size map大小
* @param keyEncoder Encodeable
* @param valueEncoder Encodeable
* @param obj 对象, 不一定是Map对象也可能是伪Map对象
*
* @return 返回-1表示还没有写入对象内容大于-1表示已写入对象内容返回对象内容大小
*/
public abstract void writeMapB(int size);
public abstract int writeMapB(int size, Encodeable<Writer, Object> keyEncoder, Encodeable<Writer, Object> valueEncoder, Object obj);
/**
* 输出一个Map中key与value间的间隔符
@@ -137,9 +232,11 @@ public abstract class Writer {
/**
* 输出一个字段名
*
* @param attribute 字段的Attribute对象
* @param fieldName 字段名称
* @param fieldType 字段类型
* @param fieldPos 字段顺序
*/
public abstract void writeFieldName(Attribute attribute);
public abstract void writeFieldName(String fieldName, Type fieldType, int fieldPos);
/**
* 写入一个boolean值
@@ -155,6 +252,13 @@ public abstract class Writer {
*/
public abstract void writeByte(byte value);
/**
* 写入byte[]
*
* @param values byte[]
*/
public abstract void writeByteArray(byte[] values);
/**
* 写入一个char值
*
@@ -210,4 +314,11 @@ public abstract class Writer {
* @param value String值
*/
public abstract void writeString(String value);
/**
* 写入一个StringConvertWrapper值
*
* @param value StringConvertWrapper值
*/
public abstract void writeWrapper(StringWrapper value);
}

View File

@@ -8,6 +8,7 @@ package org.redkale.convert.bson;
import java.nio.*;
import org.redkale.convert.*;
import static org.redkale.convert.Reader.SIGN_NULL;
import org.redkale.convert.ext.ByteSimpledCoder;
import org.redkale.util.*;
/**
@@ -48,16 +49,38 @@ public class BsonByteBufferReader extends BsonReader {
return mask == null ? currentBuffer.get(currentBuffer.position()) : mask.unmask(currentBuffer.get(currentBuffer.position()));
}
@Override
public int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valueDecoder) {
short bt = readShort();
if (bt == Reader.SIGN_NULL) return bt;
short lt = readShort();
byte kt = readByte();
byte vt = readByte();
if (typevals != null) {
typevals[0] = kt;
typevals[1] = vt;
}
return (bt & 0xffff) << 16 | (lt & 0xffff);
}
/**
* 判断下一个非空白字节是否为[
*
* @param member DeMember
* @param typevals byte[]
* @param componentDecoder Decodeable
*
* @return 数组长度或 SIGN_NULL
*/
@Override
public final int readArrayB() {
public final int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) {
short bt = readShort();
if (bt == Reader.SIGN_NULL) return bt;
short lt = readShort();
if (componentDecoder != null && componentDecoder != ByteSimpledCoder.instance) {
byte comval = readByte();
if (typevals != null) typevals[0] = comval;
}
return (bt & 0xffff) << 16 | (lt & 0xffff);
}
//------------------------------------------------------------

View File

@@ -131,7 +131,9 @@ public class BsonByteBufferWriter extends BsonWriter {
@Override
protected boolean recycle() {
super.recycle();
this.index = 0;
this.specify = null;
this.buffers = null;
return false;
}

View File

@@ -37,7 +37,7 @@ import org.redkale.util.*;
*
* @author zhangjx
*/
public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
private static final ObjectPool<BsonReader> readerPool = BsonReader.createPool(Integer.getInteger("convert.bson.pool.size", 16));
@@ -60,8 +60,18 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
}
@Override
public boolean isBinary() {
return true;
public BsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc) {
return newConvert(fieldFunc, null);
}
@Override
public BsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc, Function<Object, ConvertField[]> objExtFunc) {
return new BsonConvert(getFactory(), tiny) {
@Override
protected <S extends BsonWriter> S configWrite(S writer) {
return fieldFunc(writer, fieldFunc, objExtFunc);
}
};
}
//------------------------------ reader -----------------------------------------------------------
@@ -78,16 +88,16 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
}
public void offerBsonReader(final BsonReader in) {
if (in != null) readerPool.offer(in);
if (in != null) readerPool.accept(in);
}
//------------------------------ writer -----------------------------------------------------------
public BsonByteBufferWriter pollBsonWriter(final Supplier<ByteBuffer> supplier) {
return new BsonByteBufferWriter(tiny, supplier);
return configWrite(new BsonByteBufferWriter(tiny, supplier));
}
public BsonWriter pollBsonWriter(final OutputStream out) {
return new BsonStreamWriter(tiny, out);
return configWrite(new BsonStreamWriter(tiny, out));
}
public BsonWriter pollBsonWriter() {
@@ -95,42 +105,48 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
}
public void offerBsonWriter(final BsonWriter out) {
if (out != null) writerPool.offer(out);
if (out != null) writerPool.accept(out);
}
//------------------------------ convertFrom -----------------------------------------------------------
@Override
public <T> T convertFrom(final Type type, final byte[] bytes) {
if (bytes == null) return null;
return convertFrom(type, bytes, 0, bytes.length);
}
@SuppressWarnings("unchecked")
public <T> T convertFrom(final Type type, final byte[] bytes, final int start, final int len) {
if (type == null) return null;
final BsonReader in = readerPool.get();
in.setBytes(bytes, start, len);
@SuppressWarnings("unchecked")
T rs = (T) factory.loadDecoder(type).convertFrom(in);
readerPool.offer(in);
readerPool.accept(in);
return rs;
}
@SuppressWarnings("unchecked")
public <T> T convertFrom(final Type type, final InputStream in) {
if (type == null || in == null) return null;
return (T) factory.loadDecoder(type).convertFrom(new BsonStreamReader(in));
}
@Override
@SuppressWarnings("unchecked")
public <T> T convertFrom(final Type type, final ByteBuffer... buffers) {
if (type == null || buffers.length < 1) return null;
return (T) factory.loadDecoder(type).convertFrom(new BsonByteBufferReader((ConvertMask) null, buffers));
}
@Override
@SuppressWarnings("unchecked")
public <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers) {
if (type == null || buffers.length < 1) return null;
return (T) factory.loadDecoder(type).convertFrom(new BsonByteBufferReader(mask, buffers));
}
@SuppressWarnings("unchecked")
public <T> T convertFrom(final Type type, final BsonReader reader) {
if (type == null) return null;
@SuppressWarnings("unchecked")
@@ -139,47 +155,67 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
}
//------------------------------ convertTo -----------------------------------------------------------
@Override
public byte[] convertTo(final Object value) {
if (value == null) {
final BsonWriter out = writerPool.get().tiny(tiny);
out.writeNull();
byte[] result = out.toArray();
writerPool.offer(out);
writerPool.accept(out);
return result;
}
return convertTo(value.getClass(), value);
}
@Override
public byte[] convertTo(final Type type, final Object value) {
if (type == null) return null;
final BsonWriter out = writerPool.get().tiny(tiny);
factory.loadEncoder(type).convertTo(out, value);
byte[] result = out.toArray();
writerPool.offer(out);
writerPool.accept(out);
return result;
}
@Override
public byte[] convertMapTo(final Object... values) {
if (values == null) return null;
final BsonWriter out = writerPool.get().tiny(tiny);
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
byte[] result = out.toArray();
writerPool.accept(out);
return result;
}
public void convertTo(final OutputStream out, final Object value) {
if (value == null) {
new BsonStreamWriter(tiny, out).writeNull();
pollBsonWriter(out).writeNull();
} else {
factory.loadEncoder(value.getClass()).convertTo(new BsonStreamWriter(tiny, out), value);
factory.loadEncoder(value.getClass()).convertTo(pollBsonWriter(out), value);
}
}
public void convertTo(final OutputStream out, final Type type, final Object value) {
if (type == null) return;
if (value == null) {
new BsonStreamWriter(tiny, out).writeNull();
pollBsonWriter(out).writeNull();
} else {
factory.loadEncoder(type).convertTo(new BsonStreamWriter(tiny, out), value);
factory.loadEncoder(type).convertTo(pollBsonWriter(out), value);
}
}
public void convertMapTo(final OutputStream out, final Object... values) {
if (values == null) {
pollBsonWriter(out).writeNull();
} else {
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(pollBsonWriter(out), values);
}
}
@Override
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
if (supplier == null) return null;
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
BsonByteBufferWriter out = pollBsonWriter(supplier);
if (value == null) {
out.writeNull();
} else {
@@ -191,7 +227,7 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
@Override
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
if (supplier == null || type == null) return null;
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
BsonByteBufferWriter out = pollBsonWriter(supplier);
if (value == null) {
out.writeNull();
} else {
@@ -200,6 +236,18 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
return out.toBuffers();
}
@Override
public ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values) {
if (supplier == null) return null;
BsonByteBufferWriter out = pollBsonWriter(supplier);
if (values == null) {
out.writeNull();
} else {
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
}
return out.toBuffers();
}
public void convertTo(final BsonWriter writer, final Object value) {
if (value == null) {
writer.writeNull();
@@ -213,6 +261,14 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
factory.loadEncoder(type).convertTo(writer, value);
}
public void convertMapTo(final BsonWriter writer, final Object... values) {
if (values == null) {
writer.writeNull();
} else {
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
}
}
public BsonWriter convertToWriter(final Object value) {
if (value == null) return null;
return convertToWriter(value.getClass(), value);
@@ -225,4 +281,9 @@ public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
return out;
}
public BsonWriter convertMapToWriter(final Object... values) {
final BsonWriter out = writerPool.get().tiny(tiny);
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
return out;
}
}

View File

@@ -6,8 +6,12 @@
package org.redkale.convert.bson;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Stream;
import org.redkale.convert.*;
import org.redkale.util.AnyValue;
import org.redkale.convert.ext.*;
import org.redkale.util.*;
/**
* BSON的ConvertFactory
@@ -26,6 +30,16 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
static final Encodeable objectEncoder = instance.loadEncoder(Object.class);
static final Decodeable skipArrayDecoder = new SkipArrayDecoder(instance, Object[].class);
static final Decodeable skipCollectionDecoder = new SkipCollectionDecoder(instance, new TypeToken<Collection<Object>>() {
}.getType());
static final Decodeable skipStreamDecoder = new SkipStreamDecoder(instance, new TypeToken<Stream<Object>>() {
}.getType());
static final Decodeable skipMapDecoder = new SkipMapDecoder(instance, Map.class);
static {
instance.register(Serializable.class, objectDecoder);
instance.register(Serializable.class, objectEncoder);
@@ -84,4 +98,115 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
return true;
}
@Override
public boolean isFieldSort() {
return true;
}
protected static byte typeEnum(final Type type) {
return typeEnum(TypeToken.typeToClass(type));
}
protected static byte typeEnum(final Class type) {
Objects.requireNonNull(type);
byte typeval = 127; //字段的类型值
if (type == boolean.class || type == Boolean.class) {
typeval = 11;
} else if (type == byte.class || type == Byte.class) {
typeval = 12;
} else if (type == short.class || type == Short.class) {
typeval = 13;
} else if (type == char.class || type == Character.class) {
typeval = 14;
} else if (type == int.class || type == Integer.class) {
typeval = 15;
} else if (type == long.class || type == Long.class) {
typeval = 16;
} else if (type == float.class || type == Float.class) {
typeval = 17;
} else if (type == double.class || type == Double.class) {
typeval = 18;
} else if (type == String.class) {
typeval = 19;
} else if (type == boolean[].class || type == Boolean[].class) {
typeval = 21;
} else if (type == byte[].class || type == Byte[].class) {
typeval = 22;
} else if (type == short[].class || type == Short[].class) {
typeval = 23;
} else if (type == char[].class || type == Character[].class) {
typeval = 24;
} else if (type == int[].class || type == Integer[].class) {
typeval = 25;
} else if (type == long[].class || type == Long[].class) {
typeval = 26;
} else if (type == float[].class || type == Float[].class) {
typeval = 27;
} else if (type == double[].class || type == Double[].class) {
typeval = 28;
} else if (type == String[].class) {
typeval = 29;
} else if (type.isArray()) {
typeval = 81;
} else if (Collection.class.isAssignableFrom(type)) {
typeval = 82;
} else if (Stream.class.isAssignableFrom(type)) {
typeval = 83;
} else if (Map.class.isAssignableFrom(type)) {
typeval = 84;
}
return typeval;
}
protected static Decodeable typeEnum(final byte typeval) {
switch (typeval) {
case 11:
return BoolSimpledCoder.instance;
case 12:
return ByteSimpledCoder.instance;
case 13:
return ShortSimpledCoder.instance;
case 14:
return CharSimpledCoder.instance;
case 15:
return IntSimpledCoder.instance;
case 16:
return LongSimpledCoder.instance;
case 17:
return FloatSimpledCoder.instance;
case 18:
return DoubleSimpledCoder.instance;
case 19:
return StringSimpledCoder.instance;
case 21:
return BoolArraySimpledCoder.instance;
case 22:
return ByteArraySimpledCoder.instance;
case 23:
return ShortArraySimpledCoder.instance;
case 24:
return CharArraySimpledCoder.instance;
case 25:
return IntArraySimpledCoder.instance;
case 26:
return LongArraySimpledCoder.instance;
case 27:
return FloatArraySimpledCoder.instance;
case 28:
return DoubleArraySimpledCoder.instance;
case 29:
return StringArraySimpledCoder.instance;
case 81:
return skipArrayDecoder;
case 82:
return skipCollectionDecoder;
case 83:
return skipStreamDecoder;
case 84:
return skipMapDecoder;
case 127:
return BsonFactory.objectDecoder;
}
return null;
}
}

View File

@@ -87,58 +87,33 @@ public class BsonReader extends Reader {
* 跳过属性的值
*/
@Override
@SuppressWarnings("unchecked")
public final void skipValue() {
if (typeval == 0) return;
final byte val = this.typeval;
this.typeval = 0;
switch (val) {
case 1: readBoolean();
case 11: readBoolean();
break;
case 2: readByte();
case 12: readByte();
break;
case 3: readShort();
case 13: readShort();
break;
case 4: readChar();
case 14: readChar();
break;
case 5: readInt();
case 15: readInt();
break;
case 6: readLong();
case 16: readLong();
break;
case 7: readFloat();
case 17: readFloat();
break;
case 8: readDouble();
case 18: readDouble();
break;
case 9: readString();
case 19: readString();
break;
case 101:
BoolArraySimpledCoder.instance.convertFrom(this);
break;
case 102:
ByteArraySimpledCoder.instance.convertFrom(this);
break;
case 103:
ShortArraySimpledCoder.instance.convertFrom(this);
break;
case 104:
CharArraySimpledCoder.instance.convertFrom(this);
break;
case 105:
IntArraySimpledCoder.instance.convertFrom(this);
break;
case 106:
LongArraySimpledCoder.instance.convertFrom(this);
break;
case 107:
FloatArraySimpledCoder.instance.convertFrom(this);
break;
case 108:
DoubleArraySimpledCoder.instance.convertFrom(this);
break;
case 109:
StringArraySimpledCoder.instance.convertFrom(this);
break;
case 127:
BsonFactory.objectDecoder.convertFrom(this);
default:
Decodeable decoder = BsonFactory.typeEnum(val);
if (decoder != null) decoder.convertFrom(this);
break;
}
}
@@ -170,8 +145,17 @@ public class BsonReader extends Reader {
}
@Override
public final int readMapB() {
return readArrayB();
public int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valueDecoder) {
short bt = readShort();
if (bt == Reader.SIGN_NULL) return bt;
int rs = (bt & 0xffff) << 16 | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
byte kt = readByte();
byte vt = readByte();
if (typevals != null) {
typevals[0] = kt;
typevals[1] = vt;
}
return rs;
}
@Override
@@ -184,10 +168,15 @@ public class BsonReader extends Reader {
* @return 数组长度或SIGN_NULL
*/
@Override
public int readArrayB() {
public int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) { //componentDecoder可能为null
short bt = readShort();
if (bt == Reader.SIGN_NULL) return bt;
return (bt & 0xffff) << 16 | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
int rs = (bt & 0xffff) << 16 | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
if (componentDecoder != null && componentDecoder != ByteSimpledCoder.instance) {
byte comval = readByte();
if (typevals != null) typevals[0] = comval;
}
return rs;
}
@Override
@@ -201,13 +190,26 @@ public class BsonReader extends Reader {
public final void readBlank() {
}
@Override
public int position() {
return this.position;
}
@Override
public int readMemberContentLength(DeMember member, Decodeable decoder) {
return -1;
}
/**
* 判断对象是否存在下一个属性或者数组是否存在下一个元素
*
* @param startPosition 起始位置
* @param contentLength 内容大小, 不确定的传-1
*
* @return 是否存在
*/
@Override
public final boolean hasNext() {
public boolean hasNext(int startPosition, int contentLength) {
byte b = readByte();
if (b == SIGN_HASNEXT) return true;
if (b != SIGN_NONEXT) throw new ConvertException("hasNext option must be (" + (SIGN_HASNEXT)
@@ -247,6 +249,41 @@ public class BsonReader extends Reader {
return content[++this.position];
}
@Override
public final byte[] readByteArray() {
int len = readArrayB(null, null, null);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = readMemberContentLength(null, null);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
byte[] data = new byte[8];
int startPosition = position();
while (hasNext(startPosition, contentLength)) {
if (size >= data.length) {
byte[] newdata = new byte[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
data = newdata;
}
data[size++] = readByte();
}
readArrayE();
byte[] newdata = new byte[size];
System.arraycopy(data, 0, newdata, 0, size);
return newdata;
} else {
byte[] values = new byte[len];
for (int i = 0; i < values.length; i++) {
values[i] = readByte();
}
readArrayE();
return values;
}
}
@Override
public char readChar() {
return (char) ((0xff00 & (content[++this.position] << 8)) | (0xff & content[++this.position]));
@@ -309,4 +346,9 @@ public class BsonReader extends Reader {
return value;
}
@Override
public ValueType readType() {
throw new UnsupportedOperationException("Not supported yet.");
}
}

Some files were not shown because too many files have changed in this diff Show More