411 Commits
1.9.0 ... 1.9.7

Author SHA1 Message Date
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
193 changed files with 13690 additions and 6517 deletions

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

View File

@@ -4,6 +4,6 @@ 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\shutdown.bat"
call %APP_HOME%\bin\start.bat
call "%APP_HOME%\bin\start.bat"

View File

@@ -14,7 +14,7 @@ fi
cd "$APP_HOME"
./bin/shutdown.sh
"$APP_HOME"/bin/shutdown.sh
./bin/start.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

@@ -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

@@ -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,7 +8,7 @@
</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"/>

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>
@@ -27,7 +25,6 @@
<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.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="1234"/>
</properties>

View File

@@ -63,6 +63,7 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<compilerArgument>-parameters</compilerArgument>
<encoding>UTF-8</encoding>
<compilerArguments>
<verbose />

View File

@@ -37,11 +37,11 @@
threads 线程总数, 默认: <group>节点数*CPU核数*2
bufferCapacity: ByteBuffer的初始化大小 默认: 32K;
bufferPoolSize ByteBuffer池的大小默认: 线程总数*4
readTimeoutSecond: TCP读取超时秒数, 默认为6秒 为0表示无超时限制
writeTimeoutSecond: TCP写入超时秒数, 默认为6秒 为0表示无超时限制
readTimeoutSeconds: TCP读取超时秒数, 默认为6秒 为0表示无超时限制
writeTimeoutSeconds: TCP写入超时秒数, 默认为6秒 为0表示无超时限制
strategy: 远程请求的负载均衡策略, 必须是org.redkale.net.TransportStrategy的实现类
-->
<transport bufferCapacity="32K" bufferPoolSize="32" threads="32" readTimeoutSecond="6" writeTimeoutSecond="6"/>
<transport bufferCapacity="32K" bufferPoolSize="32" threads="32" readTimeoutSeconds="6" writeTimeoutSeconds="6"/>
<!--
一个组包含多个node 同一Service服务可以由多个进程提供这些进程称为一个GROUP且同一GROUP内的进程必须在同一机房或局域网内
@@ -85,7 +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");
@@ -114,18 +116,31 @@
excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
charset: 文本编码, 默认: UTF-8
backlog: 默认10K
threads 线程数, 默认: CPU核数*8
threads 线程数, 默认: CPU核数*32
maxconns最大连接数, 小于1表示无限制 默认: 0
maxbody: request.body最大值 默认: 64K
bufferCapacity: ByteBuffer的初始化大小 默认: 32K; (HTTP 2.0、WebSocket必须要16k以上)
bufferPoolSize ByteBuffer池的大小默认: 线程数*4
responsePoolSize Response池的大小默认: 线程数*2
readTimeoutSecond: 读操作超时秒数, 默认0 表示永久不超时
writeTimeoutSecond: 操作超时秒数, 默认0 表示永久不超时
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将共用同一个实例
@@ -216,26 +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">
</render>
<render value="org.redkalex.htel.HttpTemplateRender"/>
<!--
【节点在<server>中唯一】
当Server为HTTP协议时ResourceServlet才有效. 默认存在一个有默认属性的resource-servlet节点

View File

@@ -11,8 +11,8 @@ 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

View File

@@ -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

@@ -10,7 +10,6 @@ module org.redkale {
requires java.logging;
requires java.xml;
requires java.sql;
requires java.sql.rowset;
requires jdk.unsupported; //sun.misc.Unsafe

View File

@@ -70,7 +70,7 @@ public abstract class AnnotationVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
protected final int api;
@@ -85,7 +85,7 @@ public abstract class AnnotationVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
public AnnotationVisitor(final int api) {
this(api, null);
@@ -96,15 +96,12 @@ public abstract class AnnotationVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* 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) {
if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
throw new IllegalArgumentException();
}
this.api = api;
this.av = av;
}
@@ -118,7 +115,7 @@ public abstract class AnnotationVisitor {
* 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} or OBJECT or ARRAY sort. This
* {@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

View File

@@ -133,7 +133,7 @@ final class AnnotationWriter extends AnnotationVisitor {
*/
AnnotationWriter(final ClassWriter cw, final boolean named,
final ByteVector bv, final ByteVector parent, final int offset) {
super(Opcodes.ASM5);
super(Opcodes.ASM6);
this.cw = cw;
this.named = named;
this.bv = bv;

View File

@@ -64,7 +64,7 @@ package org.redkale.asm;
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
public class Attribute {
class Attribute {
/**
* The type of this attribute.

View File

@@ -72,31 +72,6 @@ import java.io.InputStream;
*/
public class ClassReader {
/**
* True to enable signatures support.
*/
static final boolean SIGNATURES = true;
/**
* True to enable annotations support.
*/
static final boolean ANNOTATIONS = true;
/**
* True to enable stack map frames support.
*/
static final boolean FRAMES = true;
/**
* True to enable bytecode writing support.
*/
static final boolean WRITER = true;
/**
* True to enable JSR_W and GOTO_W support.
*/
static final boolean RESIZE = true;
/**
* Flag to skip method code. If this class is set <code>CODE</code>
* attribute won't be visited. This can be used, for example, to retrieve
@@ -133,6 +108,21 @@ public class ClassReader {
*/
public static final int EXPAND_FRAMES = 8;
/**
* Flag to expand the ASM pseudo instructions into an equivalent sequence of
* standard bytecode instructions. When resolving a forward jump it may
* happen that the signed 2 bytes offset reserved for it is not sufficient
* to store the bytecode offset. In this case the jump instruction is
* replaced with a temporary ASM pseudo instruction using an unsigned 2
* bytes offset (see Label#resolve). This internal flag is used to re-read
* classes containing such instructions, in order to replace them with
* standard instructions. In addition, when this flag is used, GOTO_W and
* JSR_W are <i>not</i> converted into GOTO and JSR, to make sure that
* infinite loops where a GOTO_W is replaced with a GOTO in ClassReader and
* converted back to a GOTO_W in ClassWriter cannot occur.
*/
static final int EXPAND_ASM_INSNS = 256;
/**
* The class to be parsed. <i>The content of this array must not be
* modified. This field is intended for {@link Attribute} sub classes, and
@@ -195,8 +185,8 @@ public class ClassReader {
public ClassReader(final byte[] b, final int off, final int len) {
this.b = b;
// checks the class version
if (readShort(off + 6) > Opcodes.V1_9) {
throw new IllegalArgumentException();
if (readShort(off + 6) > Opcodes.V10) {
//throw new IllegalArgumentException();
}
// parses the constant pool
items = new int[readUnsignedShort(off + 8)];
@@ -234,6 +224,8 @@ public class ClassReader {
// case ClassWriter.CLASS:
// case ClassWriter.STR:
// case ClassWriter.MTYPE
// case ClassWriter.PACKAGE:
// case ClassWriter.MODULE:
default:
size = 3;
break;
@@ -377,7 +369,9 @@ public class ClassReader {
break;
// case ClassWriter.STR:
// case ClassWriter.CLASS:
// case ClassWriter.MTYPE
// case ClassWriter.MTYPE:
// case ClassWriter.MODULE:
// case ClassWriter.PACKAGE:
default:
item.set(tag, readUTF8(index, buf), null, null);
break;
@@ -584,11 +578,14 @@ public class ClassReader {
String enclosingOwner = null;
String enclosingName = null;
String enclosingDesc = null;
String moduleMainClass = null;
int anns = 0;
int ianns = 0;
int tanns = 0;
int itanns = 0;
int innerClasses = 0;
int module = 0;
int packages = 0;
Attribute attributes = null;
u = getAttributes();
@@ -607,13 +604,11 @@ public class ClassReader {
enclosingName = readUTF8(items[item], c);
enclosingDesc = readUTF8(items[item] + 2, c);
}
} else if (SIGNATURES && "Signature".equals(attrName)) {
} else if ("Signature".equals(attrName)) {
signature = readUTF8(u + 8, c);
} else if (ANNOTATIONS
&& "RuntimeVisibleAnnotations".equals(attrName)) {
} else if ("RuntimeVisibleAnnotations".equals(attrName)) {
anns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeVisibleTypeAnnotations".equals(attrName)) {
} else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
tanns = u + 8;
} else if ("Deprecated".equals(attrName)) {
access |= Opcodes.ACC_DEPRECATED;
@@ -623,12 +618,16 @@ public class ClassReader {
} else if ("SourceDebugExtension".equals(attrName)) {
int len = readInt(u + 4);
sourceDebug = readUTF(u + 8, len, new char[len]);
} else if (ANNOTATIONS
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
} else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
ianns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
} else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
itanns = u + 8;
} else if ("Module".equals(attrName)) {
module = u + 8;
} else if ("ModuleMainClass".equals(attrName)) {
moduleMainClass = readClass(u + 8, c);
} else if ("ModulePackages".equals(attrName)) {
packages = u + 10;
} else if ("BootstrapMethods".equals(attrName)) {
int[] bootstrapMethods = new int[readUnsignedShort(u + 8)];
for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) {
@@ -657,6 +656,12 @@ public class ClassReader {
classVisitor.visitSource(sourceFile, sourceDebug);
}
// visits the module info and associated attributes
if (module != 0) {
readModule(classVisitor, context, module,
moduleMainClass, packages);
}
// visits the outer class
if (enclosingOwner != null) {
classVisitor.visitOuterClass(enclosingOwner, enclosingName,
@@ -664,19 +669,19 @@ public class ClassReader {
}
// visits the class annotations and type annotations
if (ANNOTATIONS && anns != 0) {
if (anns != 0) {
for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true,
classVisitor.visitAnnotation(readUTF8(v, c), true));
}
}
if (ANNOTATIONS && ianns != 0) {
if (ianns != 0) {
for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true,
classVisitor.visitAnnotation(readUTF8(v, c), false));
}
}
if (ANNOTATIONS && tanns != 0) {
if (tanns != 0) {
for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true,
@@ -684,7 +689,7 @@ public class ClassReader {
context.typePath, readUTF8(v, c), true));
}
}
if (ANNOTATIONS && itanns != 0) {
if (itanns != 0) {
for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true,
@@ -726,6 +731,120 @@ public class ClassReader {
classVisitor.visitEnd();
}
/**
* Reads the module attribute and visit it.
*
* @param classVisitor
* the current class visitor
* @param context
* information about the class being parsed.
* @param u
* start offset of the module attribute in the class file.
* @param mainClass
* name of the main class of a module or null.
* @param packages
* start offset of the concealed package attribute.
*/
private void readModule(final ClassVisitor classVisitor,
final Context context, int u,
final String mainClass, int packages) {
char[] buffer = context.buffer;
// reads module name, flags and version
String name = readModule(u, buffer);
int flags = readUnsignedShort(u + 2);
String version = readUTF8(u + 4, buffer);
u += 6;
ModuleVisitor mv = classVisitor.visitModule(name, flags, version);
if (mv == null) {
return;
}
// module attributes (main class, packages)
if (mainClass != null) {
mv.visitMainClass(mainClass);
}
if (packages != 0) {
for (int i = readUnsignedShort(packages - 2); i > 0; --i) {
String packaze = readPackage(packages, buffer);
mv.visitPackage(packaze);
packages += 2;
}
}
// reads requires
u += 2;
for (int i = readUnsignedShort(u - 2); i > 0; --i) {
String module = readModule(u, buffer);
int access = readUnsignedShort(u + 2);
String requireVersion = readUTF8(u + 4, buffer);
mv.visitRequire(module, access, requireVersion);
u += 6;
}
// reads exports
u += 2;
for (int i = readUnsignedShort(u - 2); i > 0; --i) {
String export = readPackage(u, buffer);
int access = readUnsignedShort(u + 2);
int exportToCount = readUnsignedShort(u + 4);
u += 6;
String[] tos = null;
if (exportToCount != 0) {
tos = new String[exportToCount];
for (int j = 0; j < tos.length; ++j) {
tos[j] = readModule(u, buffer);
u += 2;
}
}
mv.visitExport(export, access, tos);
}
// reads opens
u += 2;
for (int i = readUnsignedShort(u - 2); i > 0; --i) {
String open = readPackage(u, buffer);
int access = readUnsignedShort(u + 2);
int openToCount = readUnsignedShort(u + 4);
u += 6;
String[] tos = null;
if (openToCount != 0) {
tos = new String[openToCount];
for (int j = 0; j < tos.length; ++j) {
tos[j] = readModule(u, buffer);
u += 2;
}
}
mv.visitOpen(open, access, tos);
}
// read uses
u += 2;
for (int i = readUnsignedShort(u - 2); i > 0; --i) {
mv.visitUse(readClass(u, buffer));
u += 2;
}
// read provides
u += 2;
for (int i = readUnsignedShort(u - 2); i > 0; --i) {
String service = readClass(u, buffer);
int provideWithCount = readUnsignedShort(u + 2);
u += 4;
String[] withs = new String[provideWithCount];
for (int j = 0; j < withs.length; ++j) {
withs[j] = readClass(u, buffer);
u += 2;
}
mv.visitProvide(service, withs);
}
mv.visitEnd();
}
/**
* Reads a field and makes the given visitor visit it.
*
@@ -762,24 +881,20 @@ public class ClassReader {
if ("ConstantValue".equals(attrName)) {
int item = readUnsignedShort(u + 8);
value = item == 0 ? null : readConst(item, c);
} else if (SIGNATURES && "Signature".equals(attrName)) {
} else if ("Signature".equals(attrName)) {
signature = readUTF8(u + 8, c);
} else if ("Deprecated".equals(attrName)) {
access |= Opcodes.ACC_DEPRECATED;
} else if ("Synthetic".equals(attrName)) {
access |= Opcodes.ACC_SYNTHETIC
| ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
} else if (ANNOTATIONS
&& "RuntimeVisibleAnnotations".equals(attrName)) {
} else if ("RuntimeVisibleAnnotations".equals(attrName)) {
anns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeVisibleTypeAnnotations".equals(attrName)) {
} else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
tanns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
} else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
ianns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
} else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
itanns = u + 8;
} else {
Attribute attr = readAttribute(context.attrs, attrName, u + 8,
@@ -801,19 +916,19 @@ public class ClassReader {
}
// visits the field annotations and type annotations
if (ANNOTATIONS && anns != 0) {
if (anns != 0) {
for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true,
fv.visitAnnotation(readUTF8(v, c), true));
}
}
if (ANNOTATIONS && ianns != 0) {
if (ianns != 0) {
for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true,
fv.visitAnnotation(readUTF8(v, c), false));
}
}
if (ANNOTATIONS && tanns != 0) {
if (tanns != 0) {
for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true,
@@ -821,7 +936,7 @@ public class ClassReader {
context.typePath, readUTF8(v, c), true));
}
}
if (ANNOTATIONS && itanns != 0) {
if (itanns != 0) {
for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true,
@@ -895,32 +1010,26 @@ public class ClassReader {
exceptions[j] = readClass(exception, c);
exception += 2;
}
} else if (SIGNATURES && "Signature".equals(attrName)) {
} else if ("Signature".equals(attrName)) {
signature = readUTF8(u + 8, c);
} else if ("Deprecated".equals(attrName)) {
context.access |= Opcodes.ACC_DEPRECATED;
} else if (ANNOTATIONS
&& "RuntimeVisibleAnnotations".equals(attrName)) {
} else if ("RuntimeVisibleAnnotations".equals(attrName)) {
anns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeVisibleTypeAnnotations".equals(attrName)) {
} else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
tanns = u + 8;
} else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) {
} else if ("AnnotationDefault".equals(attrName)) {
dann = u + 8;
} else if ("Synthetic".equals(attrName)) {
context.access |= Opcodes.ACC_SYNTHETIC
| ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
} else if (ANNOTATIONS
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
} else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
ianns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
} else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
itanns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeVisibleParameterAnnotations".equals(attrName)) {
} else if ("RuntimeVisibleParameterAnnotations".equals(attrName)) {
mpanns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeInvisibleParameterAnnotations".equals(attrName)) {
} else if ("RuntimeInvisibleParameterAnnotations".equals(attrName)) {
impanns = u + 8;
} else if ("MethodParameters".equals(attrName)) {
methodParameters = u + 8;
@@ -953,7 +1062,7 @@ public class ClassReader {
* access, name and descriptor can have been changed, this is not
* important since they are not copied as is from the reader).
*/
if (WRITER && mv instanceof MethodWriter) {
if (mv instanceof MethodWriter) {
MethodWriter mw = (MethodWriter) mv;
if (mw.cw.cr == this && signature == mw.signature) {
boolean sameExceptions = false;
@@ -990,26 +1099,26 @@ public class ClassReader {
}
// visits the method annotations
if (ANNOTATIONS && dann != 0) {
if (dann != 0) {
AnnotationVisitor dv = mv.visitAnnotationDefault();
readAnnotationValue(dann, c, null, dv);
if (dv != null) {
dv.visitEnd();
}
}
if (ANNOTATIONS && anns != 0) {
if (anns != 0) {
for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true,
mv.visitAnnotation(readUTF8(v, c), true));
}
}
if (ANNOTATIONS && ianns != 0) {
if (ianns != 0) {
for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true,
mv.visitAnnotation(readUTF8(v, c), false));
}
}
if (ANNOTATIONS && tanns != 0) {
if (tanns != 0) {
for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true,
@@ -1017,7 +1126,7 @@ public class ClassReader {
context.typePath, readUTF8(v, c), true));
}
}
if (ANNOTATIONS && itanns != 0) {
if (itanns != 0) {
for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true,
@@ -1025,10 +1134,10 @@ public class ClassReader {
context.typePath, readUTF8(v, c), false));
}
}
if (ANNOTATIONS && mpanns != 0) {
if (mpanns != 0) {
readParameterAnnotations(mv, context, mpanns, true);
}
if (ANNOTATIONS && impanns != 0) {
if (impanns != 0) {
readParameterAnnotations(mv, context, impanns, false);
}
@@ -1075,7 +1184,7 @@ public class ClassReader {
int codeStart = u;
int codeEnd = u + codeLength;
Label[] labels = context.labels = new Label[codeLength + 2];
readLabel(codeLength + 1, labels);
createLabel(codeLength + 1, labels);
while (u < codeEnd) {
int offset = u - codeStart;
int opcode = b[u] & 0xFF;
@@ -1085,11 +1194,16 @@ public class ClassReader {
u += 1;
break;
case ClassWriter.LABEL_INSN:
readLabel(offset + readShort(u + 1), labels);
createLabel(offset + readShort(u + 1), labels);
u += 3;
break;
case ClassWriter.ASM_LABEL_INSN:
createLabel(offset + readUnsignedShort(u + 1), labels);
u += 3;
break;
case ClassWriter.LABELW_INSN:
readLabel(offset + readInt(u + 1), labels);
case ClassWriter.ASM_LABELW_INSN:
createLabel(offset + readInt(u + 1), labels);
u += 5;
break;
case ClassWriter.WIDE_INSN:
@@ -1104,9 +1218,9 @@ public class ClassReader {
// skips 0 to 3 padding bytes
u = u + 4 - (offset & 3);
// reads instruction
readLabel(offset + readInt(u), labels);
createLabel(offset + readInt(u), labels);
for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) {
readLabel(offset + readInt(u + 12), labels);
createLabel(offset + readInt(u + 12), labels);
u += 4;
}
u += 12;
@@ -1115,9 +1229,9 @@ public class ClassReader {
// skips 0 to 3 padding bytes
u = u + 4 - (offset & 3);
// reads instruction
readLabel(offset + readInt(u), labels);
createLabel(offset + readInt(u), labels);
for (int i = readInt(u + 4); i > 0; --i) {
readLabel(offset + readInt(u + 12), labels);
createLabel(offset + readInt(u + 12), labels);
u += 8;
}
u += 8;
@@ -1147,9 +1261,9 @@ public class ClassReader {
// reads the try catch entries to find the labels, and also visits them
for (int i = readUnsignedShort(u); i > 0; --i) {
Label start = readLabel(readUnsignedShort(u + 2), labels);
Label end = readLabel(readUnsignedShort(u + 4), labels);
Label handler = readLabel(readUnsignedShort(u + 6), labels);
Label start = createLabel(readUnsignedShort(u + 2), labels);
Label end = createLabel(readUnsignedShort(u + 4), labels);
Label handler = createLabel(readUnsignedShort(u + 6), labels);
String type = readUTF8(items[readUnsignedShort(u + 8)], c);
mv.visitTryCatchBlock(start, end, handler, type);
u += 8;
@@ -1180,13 +1294,9 @@ public class ClassReader {
varTable = u + 8;
for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
int label = readUnsignedShort(v + 10);
if (labels[label] == null) {
readLabel(label, labels).status |= Label.DEBUG;
}
createDebugLabel(label, labels);
label += readUnsignedShort(v + 12);
if (labels[label] == null) {
readLabel(label, labels).status |= Label.DEBUG;
}
createDebugLabel(label, labels);
v += 10;
}
}
@@ -1196,9 +1306,7 @@ public class ClassReader {
if ((context.flags & SKIP_DEBUG) == 0) {
for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
int label = readUnsignedShort(v + 10);
if (labels[label] == null) {
readLabel(label, labels).status |= Label.DEBUG;
}
createDebugLabel(label, labels);
Label l = labels[label];
while (l.line > 0) {
if (l.next == null) {
@@ -1210,17 +1318,15 @@ public class ClassReader {
v += 4;
}
}
} else if (ANNOTATIONS
&& "RuntimeVisibleTypeAnnotations".equals(attrName)) {
} else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
tanns = readTypeAnnotations(mv, context, u + 8, true);
ntoff = tanns.length == 0 || readByte(tanns[0]) < 0x43 ? -1
: readUnsignedShort(tanns[0] + 1);
} else if (ANNOTATIONS
&& "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
} else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
itanns = readTypeAnnotations(mv, context, u + 8, false);
nitoff = itanns.length == 0 || readByte(itanns[0]) < 0x43 ? -1
: readUnsignedShort(itanns[0] + 1);
} else if (FRAMES && "StackMapTable".equals(attrName)) {
} else if ("StackMapTable".equals(attrName)) {
if ((context.flags & SKIP_FRAMES) == 0) {
stackMap = u + 10;
stackMapSize = readInt(u + 4);
@@ -1244,7 +1350,7 @@ public class ClassReader {
* this by parsing the stack map table without a full decoding
* (see below).
*/
} else if (FRAMES && "StackMap".equals(attrName)) {
} else if ("StackMap".equals(attrName)) {
if ((context.flags & SKIP_FRAMES) == 0) {
zip = false;
stackMap = u + 10;
@@ -1273,7 +1379,7 @@ public class ClassReader {
u += 2;
// generates the first (implicit) stack map frame
if (FRAMES && stackMap != 0) {
if (stackMap != 0) {
/*
* for the first explicit frame the offset is not offset_delta + 1
* but only offset_delta; setting the implicit frame offset to -1
@@ -1306,14 +1412,31 @@ public class ClassReader {
int v = readUnsignedShort(i + 1);
if (v >= 0 && v < codeLength) {
if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) {
readLabel(v, labels);
createLabel(v, labels);
}
}
}
}
}
if ((context.flags & EXPAND_ASM_INSNS) != 0
&& (context.flags & EXPAND_FRAMES) != 0) {
// Expanding the ASM pseudo instructions can introduce F_INSERT
// frames, even if the method does not currently have any frame.
// Also these inserted frames must be computed by simulating the
// effect of the bytecode instructions one by one, starting from the
// first one and the last existing frame (or the implicit first
// one). Finally, due to the way MethodWriter computes this (with
// the compute = INSERTED_FRAMES option), MethodWriter needs to know
// maxLocals before the first instruction is visited. For all these
// reasons we always visit the implicit first frame in this case
// (passing only maxLocals - the rest can be and is computed in
// MethodWriter).
mv.visitFrame(Opcodes.F_NEW, maxLocals, null, 0, null);
}
// visits the instructions
int opcodeDelta = (context.flags & EXPAND_ASM_INSNS) == 0 ? -33 : 0;
boolean insertFrame = false;
u = codeStart;
while (u < codeEnd) {
int offset = u - codeStart;
@@ -1334,7 +1457,7 @@ public class ClassReader {
}
// visits the frame for this offset, if any
while (FRAMES && frame != null
while (frame != null
&& (frame.offset == offset || frame.offset == -1)) {
// if there is a frame for this offset, makes the visitor visit
// it, and reads the next frame if there is one.
@@ -1346,6 +1469,9 @@ public class ClassReader {
mv.visitFrame(frame.mode, frame.localDiff, frame.local,
frame.stackCount, frame.stack);
}
// if there is already a frame for this offset, there is no
// need to insert a new one.
insertFrame = false;
}
if (frameCount > 0) {
stackMap = readFrame(stackMap, zip, unzip, frame);
@@ -1354,6 +1480,13 @@ public class ClassReader {
frame = null;
}
}
// inserts a frame for this offset, if requested by setting
// insertFrame to true during the previous iteration. The actual
// frame content will be computed in MethodWriter.
if (insertFrame) {
mv.visitFrame(ClassWriter.F_INSERT, 0, null, 0, null);
insertFrame = false;
}
// visits the instruction at this offset
int opcode = b[u] & 0xFF;
@@ -1378,9 +1511,47 @@ public class ClassReader {
u += 3;
break;
case ClassWriter.LABELW_INSN:
mv.visitJumpInsn(opcode - 33, labels[offset + readInt(u + 1)]);
mv.visitJumpInsn(opcode + opcodeDelta, labels[offset
+ readInt(u + 1)]);
u += 5;
break;
case ClassWriter.ASM_LABEL_INSN: {
// changes temporary opcodes 202 to 217 (inclusive), 218
// and 219 to IFEQ ... JSR (inclusive), IFNULL and
// IFNONNULL
opcode = opcode < 218 ? opcode - 49 : opcode - 20;
Label target = labels[offset + readUnsignedShort(u + 1)];
// replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
// <l> with IFNOTxxx <L> GOTO_W <l> L:..., where IFNOTxxx is
// the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
// and where <L> designates the instruction just after
// the GOTO_W.
if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) {
mv.visitJumpInsn(opcode + 33, target);
} else {
opcode = opcode <= 166 ? ((opcode + 1) ^ 1) - 1
: opcode ^ 1;
Label endif = createLabel(offset + 3, labels);
mv.visitJumpInsn(opcode, endif);
mv.visitJumpInsn(200, target); // GOTO_W
// endif designates the instruction just after GOTO_W,
// and is visited as part of the next instruction. Since
// it is a jump target, we need to insert a frame here.
insertFrame = true;
}
u += 3;
break;
}
case ClassWriter.ASM_LABELW_INSN: {
// replaces the pseudo GOTO_W instruction with a real one.
mv.visitJumpInsn(200, labels[offset + readInt(u + 1)]);
// The instruction just after is a jump target (because pseudo
// GOTO_W are used in patterns IFNOTxxx <L> GOTO_W <l> L:...,
// see MethodWriter), so we need to insert a frame here.
insertFrame = true;
u += 5;
break;
}
case ClassWriter.WIDE_INSN:
opcode = b[u + 1] & 0xFF;
if (opcode == Opcodes.IINC) {
@@ -1636,8 +1807,8 @@ public class ClassReader {
for (int j = readUnsignedShort(u + 1); j > 0; --j) {
int start = readUnsignedShort(u + 3);
int length = readUnsignedShort(u + 5);
readLabel(start, context.labels);
readLabel(start + length, context.labels);
createLabel(start, context.labels);
createLabel(start + length, context.labels);
u += 6;
}
u += 3;
@@ -1716,8 +1887,8 @@ public class ClassReader {
for (int i = 0; i < n; ++i) {
int start = readUnsignedShort(u);
int length = readUnsignedShort(u + 2);
context.start[i] = readLabel(start, context.labels);
context.end[i] = readLabel(start + length, context.labels);
context.start[i] = createLabel(start, context.labels);
context.end[i] = createLabel(start + length, context.labels);
context.index[i] = readUnsignedShort(u + 4);
u += 6;
}
@@ -2137,7 +2308,7 @@ public class ClassReader {
}
}
frame.offset += delta + 1;
readLabel(frame.offset, labels);
createLabel(frame.offset, labels);
return stackMap;
}
@@ -2190,7 +2361,7 @@ public class ClassReader {
v += 2;
break;
default: // Uninitialized
frame[index] = readLabel(readUnsignedShort(v), labels);
frame[index] = createLabel(readUnsignedShort(v), labels);
v += 2;
}
return v;
@@ -2216,6 +2387,39 @@ public class ClassReader {
return labels[offset];
}
/**
* Creates a label without the Label.DEBUG flag set, for the given offset.
* The label is created with a call to {@link #readLabel} and its
* Label.DEBUG flag is cleared.
*
* @param offset
* a bytecode offset in a method.
* @param labels
* the already created labels, indexed by their offset.
* @return a Label without the Label.DEBUG flag set.
*/
private Label createLabel(int offset, Label[] labels) {
Label label = readLabel(offset, labels);
label.status &= ~Label.DEBUG;
return label;
}
/**
* Creates a label with the Label.DEBUG flag set, if there is no already
* existing label for the given offset (otherwise does nothing). The label
* is created with a call to {@link #readLabel}.
*
* @param offset
* a bytecode offset in a method.
* @param labels
* the already created labels, indexed by their offset.
*/
private void createDebugLabel(int offset, Label[] labels) {
if (labels[offset] == null) {
readLabel(offset, labels).status |= Label.DEBUG;
}
}
/**
* Returns the start index of the attribute_info structure of this class.
*
@@ -2470,6 +2674,20 @@ public class ClassReader {
return new String(buf, 0, strLen);
}
/**
* Read a stringish constant item (CONSTANT_Class, CONSTANT_String,
* CONSTANT_MethodType, CONSTANT_Module or CONSTANT_Package
* @param index
* @param buf
* @return
*/
private String readStringish(final int index, final char[] buf) {
// computes the start index of the item in b
// and reads the CONSTANT_Utf8 item designated by
// the first two bytes of this item
return readUTF8(items[readUnsignedShort(index)], buf);
}
/**
* Reads a class constant pool item in {@link #b b}. <i>This method is
* intended for {@link Attribute} sub classes, and is normally not needed by
@@ -2484,44 +2702,41 @@ public class ClassReader {
* @return the String corresponding to the specified class item.
*/
public String readClass(final int index, final char[] buf) {
// computes the start index of the CONSTANT_Class item in b
// and reads the CONSTANT_Utf8 item designated by
// the first two bytes of this CONSTANT_Class item
return readUTF8(items[readUnsignedShort(index)], buf);
return readStringish(index, buf);
}
/**
* Reads a CONSTANT_Module_info item in {@code b}. This method is intended
* for {@link Attribute} sub classes, and is normally not needed by class
* generators or adapters.
* Reads a module constant pool item in {@link #b b}. <i>This method is
* intended for {@link Attribute} sub classes, and is normally not needed by
* class generators or adapters.</i>
*
* @param index
* the start index of an unsigned short value in {@link #b b},
* whose value is the index of a module constant pool item.
* @param buf
* buffer to be used to read the item. This buffer must be
* sufficiently large. It is not automatically resized.
* @param index
* the start index of an unsigned short value in {@link #b b},
* whose value is the index of a module constant pool item.
* @param buf
* buffer to be used to read the item. This buffer must be
* sufficiently large. It is not automatically resized.
* @return the String corresponding to the specified module item.
*/
public String readModule(int index, char[] buf) {
return readUTF8(items[readUnsignedShort(index)], buf);
public String readModule(final int index, final char[] buf) {
return readStringish(index, buf);
}
/**
* Reads a CONSTANT_Package_info item in {@code b}. This method is
* intended for {@link Attribute} sub slasses, and is normally not needed
* by class generators or adapters.
* Reads a module constant pool item in {@link #b b}. <i>This method is
* intended for {@link Attribute} sub classes, and is normally not needed by
* class generators or adapters.</i>
*
* @param index
* the start index of an unsigned short value in {@link #b b},
* whose value is the index of a package constant pool item.
* @param buf
* buffer to be used to read the item. This buffer must be
* sufficiently large. It is not automatically resized.
* @return the String corresponding to the specified package item.
* @param index
* the start index of an unsigned short value in {@link #b b},
* whose value is the index of a module constant pool item.
* @param buf
* buffer to be used to read the item. This buffer must be
* sufficiently large. It is not automatically resized.
* @return the String corresponding to the specified module item.
*/
public String readPackage(int index, char[] buf) {
return readUTF8(items[readUnsignedShort(index)], buf);
public String readPackage(final int index, final char[] buf) {
return readStringish(index, buf);
}
/**
@@ -2550,8 +2765,6 @@ public class ClassReader {
case ClassWriter.DOUBLE:
return Double.longBitsToDouble(readLong(index));
case ClassWriter.CLASS:
case ClassWriter.MODULE:
case ClassWriter.PACKAGE:
return Type.getObjectType(readUTF8(index, buf));
case ClassWriter.STR:
return readUTF8(index, buf);

View File

@@ -61,7 +61,7 @@ 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>visitOuterClass</tt> ] ( <tt>visitAnnotation</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>.
@@ -72,7 +72,7 @@ public abstract class ClassVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
protected final int api;
@@ -87,7 +87,7 @@ public abstract class ClassVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
public ClassVisitor(final int api) {
this(api, null);
@@ -98,15 +98,12 @@ public abstract class ClassVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* 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) {
if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
throw new IllegalArgumentException();
}
this.api = api;
this.cv = cv;
}
@@ -160,6 +157,28 @@ public abstract class ClassVisitor {
}
}
/**
* 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.
@@ -222,9 +241,6 @@ public abstract class ClassVisitor {
*/
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (cv != null) {
return cv.visitTypeAnnotation(typeRef, typePath, desc, visible);
}

View File

@@ -87,8 +87,8 @@ public class ClassWriter extends ClassVisitor {
* {@link MethodVisitor#visitFrame} method are ignored, and the stack map
* frames are recomputed from the methods bytecode. The arguments of the
* {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and
* recomputed from the bytecode. In other words, computeFrames implies
* computeMaxs.
* recomputed from the bytecode. In other words, COMPUTE_FRAMES implies
* COMPUTE_MAXS.
*
* @see #ClassWriter(int)
*/
@@ -196,6 +196,27 @@ public class ClassWriter extends ClassVisitor {
*/
static final int WIDE_INSN = 17;
/**
* The type of the ASM pseudo instructions with an unsigned 2 bytes offset
* label (see Label#resolve).
*/
static final int ASM_LABEL_INSN = 18;
/**
* The type of the ASM pseudo instructions with a 4 bytes offset label.
*/
static final int ASM_LABELW_INSN = 19;
/**
* Represents a frame inserted between already existing frames. This kind of
* frame can only be used if the frame content can be computed from the
* previous existing frame and from the instructions between this existing
* frame and the inserted one, without any knowledge of the type hierarchy.
* This kind of frame is only used when an unconditional jump is inserted in
* a method while expanding an ASM pseudo instruction (see ClassReader).
*/
static final int F_INSERT = 256;
/**
* The instruction types of all JVM opcodes.
*/
@@ -284,7 +305,7 @@ public class ClassWriter extends ClassVisitor {
/**
* The base value for all CONSTANT_MethodHandle constant pool items.
* Internally, ASM store the 9 variations of CONSTANT_MethodHandle into 9
* different items.
* different items (from 21 to 29).
*/
static final int HANDLE_BASE = 20;
@@ -433,6 +454,11 @@ public class ClassWriter extends ClassVisitor {
*/
private ByteVector sourceDebug;
/**
* The module attribute of this class.
*/
private ModuleWriter moduleWriter;
/**
* The constant pool item that contains the name of the enclosing class of
* this class.
@@ -523,25 +549,19 @@ public class ClassWriter extends ClassVisitor {
MethodWriter lastMethod;
/**
* <tt>true</tt> if the maximum stack size and number of local variables
* must be automatically computed.
* Indicates what must be automatically computed.
*
* @see MethodWriter#compute
*/
private boolean computeMaxs;
private int compute;
/**
* <tt>true</tt> if the stack map frames must be recomputed from scratch.
* <tt>true</tt> if some methods have wide forward jumps using ASM pseudo
* instructions, which need to be expanded into sequences of standard
* bytecode instructions. In this case the class is re-read and re-written
* with a ClassReader -> ClassWriter chain to perform this transformation.
*/
private boolean computeFrames;
/**
* <tt>true</tt> if the stack map tables of this class are invalid. The
* {@link MethodWriter#resizeInstructions} method cannot transform existing
* stack map tables, and so produces potentially invalid classes when it is
* executed. In this case the class is reread and rewritten with the
* {@link #COMPUTE_FRAMES} option (the resizeInstructions method can resize
* stack map tables when this option is used).
*/
boolean invalidFrames;
boolean hasAsmInsns;
// ------------------------------------------------------------------------
// Static initializer
@@ -552,11 +572,11 @@ public class ClassWriter extends ClassVisitor {
*/
static {
int i;
byte[] b = new byte[220];
byte[] b = new byte[221];
String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD"
+ "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ "AAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAA"
+ "AAAAGGGGGGGHIFBFAAFFAARQJJKKJJJJJJJJJJJJJJJJJJ";
+ "AAAAGGGGGGGHIFBFAAFFAARQJJKKSSSSSSSSSSSSSSSSSST";
for (i = 0; i < b.length; ++i) {
b[i] = (byte) (s.charAt(i) - 'A');
}
@@ -610,8 +630,9 @@ public class ClassWriter extends ClassVisitor {
// // temporary opcodes used internally by ASM - see Label and
// MethodWriter
// for (i = 202; i < 220; ++i) {
// b[i] = LABEL_INSN;
// b[i] = ASM_LABEL_INSN;
// }
// b[220] = ASM_LABELW_INSN;
//
// // LDC(_W) instructions
// b[Constants.LDC] = LDC_INSN;
@@ -644,7 +665,7 @@ public class ClassWriter extends ClassVisitor {
* {@link #COMPUTE_FRAMES}.
*/
public ClassWriter(final int flags) {
super(Opcodes.ASM5);
super(Opcodes.ASM6);
index = 1;
pool = new ByteVector();
items = new Item[256];
@@ -653,8 +674,9 @@ public class ClassWriter extends ClassVisitor {
key2 = new Item();
key3 = new Item();
key4 = new Item();
this.computeMaxs = (flags & COMPUTE_MAXS) != 0;
this.computeFrames = (flags & COMPUTE_FRAMES) != 0;
this.compute = (flags & COMPUTE_FRAMES) != 0 ? MethodWriter.FRAMES
: ((flags & COMPUTE_MAXS) != 0 ? MethodWriter.MAXS
: MethodWriter.NOTHING);
}
/**
@@ -684,9 +706,9 @@ public class ClassWriter extends ClassVisitor {
* @param flags
* option flags that can be used to modify the default behavior
* of this class. <i>These option flags do not affect methods
* that are copied as is in the new class. This means that the
* maximum stack size nor the stack frames will be computed for
* these methods</i>. See {@link #COMPUTE_MAXS},
* that are copied as is in the new class. This means that
* neither the maximum stack size nor the stack frames will be
* computed for these methods</i>. See {@link #COMPUTE_MAXS},
* {@link #COMPUTE_FRAMES}.
*/
public ClassWriter(final ClassReader classReader, final int flags) {
@@ -705,9 +727,9 @@ public class ClassWriter extends ClassVisitor {
final String[] interfaces) {
this.version = version;
this.access = access;
this.name = (name == null) ? 0 : newClass(name);
this.name = newClass(name);
thisName = name;
if (ClassReader.SIGNATURES && signature != null) {
if (signature != null) {
this.signature = newUTF8(signature);
}
this.superName = superName == null ? 0 : newClass(superName);
@@ -731,6 +753,14 @@ public class ClassWriter extends ClassVisitor {
}
}
@Override
public final ModuleVisitor visitModule(final String name,
final int access, final String version) {
return moduleWriter = new ModuleWriter(this,
newModule(name), access,
version == null ? 0 : newUTF8(version));
}
@Override
public final void visitOuterClass(final String owner, final String name,
final String desc) {
@@ -743,9 +773,6 @@ public class ClassWriter extends ClassVisitor {
@Override
public final AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
if (!ClassReader.ANNOTATIONS) {
return null;
}
ByteVector bv = new ByteVector();
// write type, and reserve space for values count
bv.putShort(newUTF8(desc)).putShort(0);
@@ -763,9 +790,6 @@ public class ClassWriter extends ClassVisitor {
@Override
public final AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, final String desc, final boolean visible) {
if (!ClassReader.ANNOTATIONS) {
return null;
}
ByteVector bv = new ByteVector();
// write target_type and target_info
AnnotationWriter.putTarget(typeRef, typePath, bv);
@@ -805,7 +829,7 @@ public class ClassWriter extends ClassVisitor {
// and equality tests). If so we store the index of this inner class
// entry (plus one) in intVal. This hack allows duplicate detection in
// O(1) time.
Item nameItem = newClassItem(name);
Item nameItem = newStringishItem(CLASS, name);
if (nameItem.intVal == 0) {
++innerClassesCount;
innerClasses.putShort(nameItem.index);
@@ -830,7 +854,7 @@ public class ClassWriter extends ClassVisitor {
public final MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
return new MethodWriter(this, access, name, desc, signature,
exceptions, computeMaxs, computeFrames);
exceptions, compute);
}
@Override
@@ -874,7 +898,7 @@ public class ClassWriter extends ClassVisitor {
size += 8 + bootstrapMethods.length;
newUTF8("BootstrapMethods");
}
if (ClassReader.SIGNATURES && signature != 0) {
if (signature != 0) {
++attributeCount;
size += 8;
newUTF8("Signature");
@@ -912,26 +936,31 @@ public class ClassWriter extends ClassVisitor {
size += 8 + innerClasses.length;
newUTF8("InnerClasses");
}
if (ClassReader.ANNOTATIONS && anns != null) {
if (anns != null) {
++attributeCount;
size += 8 + anns.getSize();
newUTF8("RuntimeVisibleAnnotations");
}
if (ClassReader.ANNOTATIONS && ianns != null) {
if (ianns != null) {
++attributeCount;
size += 8 + ianns.getSize();
newUTF8("RuntimeInvisibleAnnotations");
}
if (ClassReader.ANNOTATIONS && tanns != null) {
if (tanns != null) {
++attributeCount;
size += 8 + tanns.getSize();
newUTF8("RuntimeVisibleTypeAnnotations");
}
if (ClassReader.ANNOTATIONS && itanns != null) {
if (itanns != null) {
++attributeCount;
size += 8 + itanns.getSize();
newUTF8("RuntimeInvisibleTypeAnnotations");
}
if (moduleWriter != null) {
attributeCount += 1 + moduleWriter.attributeCount;
size += 6 + moduleWriter.size + moduleWriter.attributesSize;
newUTF8("Module");
}
if (attrs != null) {
attributeCount += attrs.getCount();
size += attrs.getSize(this, null, 0, -1, -1);
@@ -968,7 +997,7 @@ public class ClassWriter extends ClassVisitor {
bootstrapMethodsCount);
out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length);
}
if (ClassReader.SIGNATURES && signature != 0) {
if (signature != 0) {
out.putShort(newUTF8("Signature")).putInt(2).putShort(signature);
}
if (sourceFile != 0) {
@@ -979,6 +1008,11 @@ public class ClassWriter extends ClassVisitor {
out.putShort(newUTF8("SourceDebugExtension")).putInt(len);
out.putByteArray(sourceDebug.data, 0, len);
}
if (moduleWriter != null) {
out.putShort(newUTF8("Module"));
moduleWriter.put(out);
moduleWriter.putAttributes(out);
}
if (enclosingMethodOwner != 0) {
out.putShort(newUTF8("EnclosingMethod")).putInt(4);
out.putShort(enclosingMethodOwner).putShort(enclosingMethod);
@@ -997,41 +1031,46 @@ public class ClassWriter extends ClassVisitor {
out.putInt(innerClasses.length + 2).putShort(innerClassesCount);
out.putByteArray(innerClasses.data, 0, innerClasses.length);
}
if (ClassReader.ANNOTATIONS && anns != null) {
if (anns != null) {
out.putShort(newUTF8("RuntimeVisibleAnnotations"));
anns.put(out);
}
if (ClassReader.ANNOTATIONS && ianns != null) {
if (ianns != null) {
out.putShort(newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out);
}
if (ClassReader.ANNOTATIONS && tanns != null) {
if (tanns != null) {
out.putShort(newUTF8("RuntimeVisibleTypeAnnotations"));
tanns.put(out);
}
if (ClassReader.ANNOTATIONS && itanns != null) {
if (itanns != null) {
out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations"));
itanns.put(out);
}
if (attrs != null) {
attrs.put(this, null, 0, -1, -1, out);
}
if (invalidFrames) {
if (hasAsmInsns) {
boolean hasFrames = false;
mb = firstMethod;
while (mb != null) {
hasFrames |= mb.frameCount > 0;
mb = (MethodWriter) mb.mv;
}
anns = null;
ianns = null;
attrs = null;
innerClassesCount = 0;
innerClasses = null;
bootstrapMethodsCount = 0;
bootstrapMethods = null;
moduleWriter = null;
firstField = null;
lastField = null;
firstMethod = null;
lastMethod = null;
computeMaxs = false;
computeFrames = true;
invalidFrames = false;
new ClassReader(out.data).accept(this, ClassReader.SKIP_FRAMES);
compute =
hasFrames ? MethodWriter.INSERTED_FRAMES : MethodWriter.NOTHING;
hasAsmInsns = false;
new ClassReader(out.data).accept(this,
(hasFrames ? ClassReader.EXPAND_FRAMES : 0)
| ClassReader.EXPAND_ASM_INSNS);
return toByteArray();
}
return out.data;
@@ -1078,16 +1117,16 @@ public class ClassWriter extends ClassVisitor {
double val = ((Double) cst).doubleValue();
return newDouble(val);
} else if (cst instanceof String) {
return newString((String) cst);
return newStringishItem(STR, (String) cst);
} else if (cst instanceof Type) {
Type t = (Type) cst;
int s = t.getSort();
if (s == Type.OBJECT) {
return newClassItem(t.getInternalName());
return newStringishItem(CLASS, t.getInternalName());
} else if (s == Type.METHOD) {
return newMethodTypeItem(t.getDescriptor());
return newStringishItem(MTYPE, t.getDescriptor());
} else { // s == primitive type or array
return newClassItem(t.getDescriptor());
return newStringishItem(CLASS, t.getDescriptor());
}
} else if (cst instanceof Handle) {
Handle h = (Handle) cst;
@@ -1136,20 +1175,21 @@ public class ClassWriter extends ClassVisitor {
}
/**
* Adds a class reference to the constant pool of the class being build.
* Adds a string reference, a class reference, a method type, a module
* or a package to the constant pool of the class being build.
* Does nothing if the constant pool already contains a similar item.
* <i>This method is intended for {@link Attribute} sub classes, and is
* normally not needed by class generators or adapters.</i>
*
* @param type
* a type among STR, CLASS, MTYPE, MODULE or PACKAGE
* @param value
* the internal name of the class.
* @return a new or already existing class reference item.
* string value of the reference.
* @return a new or already existing reference item.
*/
Item newClassItem(final String value) {
key2.set(CLASS, value, null, null);
Item newStringishItem(final int type, final String value) {
key2.set(type, value, null, null);
Item result = get(key2);
if (result == null) {
pool.put12(CLASS, newUTF8(value));
pool.put12(type, newUTF8(value));
result = new Item(index++, key2);
put(result);
}
@@ -1167,72 +1207,7 @@ public class ClassWriter extends ClassVisitor {
* @return the index of a new or already existing class reference item.
*/
public int newClass(final String value) {
return newClassItem(value).index;
}
/**
* Adds a module name to the constant pool.
*
* Does nothing if the constant pool already contains a similar item.
* <i>This method is intended for {@link Attribute} sub classes, and is
* normally not needed by class generators or adapters.</i>
*
* @param value
* the module name
* @return the index of a new or already existing module reference item.
*/
public int newModule(String value) {
key2.set(MODULE, value, null, null);
Item result = get(key2);
if (result == null) {
pool.put12(MODULE, newUTF8(value));
result = new Item(index++, key2);
put(result);
}
return result.index;
}
/**
* Adds a package name to the constant pool.
*
* Does nothing if the constant pool already contains a similar item.
* <i>This method is intended for {@link Attribute} sub classes, and is
* normally not needed by class generators or adapters.</i>
*
* @param value
* the internal name of the package.
* @return the index of a new or already existing package reference item.
*/
public int newPackage(String value) {
key2.set(PACKAGE, value, null, null);
Item result = get(key2);
if (result == null) {
pool.put12(PACKAGE, newUTF8(value));
result = new Item(index++, key2);
put(result);
}
return result.index;
}
/**
* Adds a method type reference to the constant pool of the class being
* build. Does nothing if the constant pool already contains a similar item.
* <i>This method is intended for {@link Attribute} sub classes, and is
* normally not needed by class generators or adapters.</i>
*
* @param methodDesc
* method descriptor of the method type.
* @return a new or already existing method type reference item.
*/
Item newMethodTypeItem(final String methodDesc) {
key2.set(MTYPE, methodDesc, null, null);
Item result = get(key2);
if (result == null) {
pool.put12(MTYPE, newUTF8(methodDesc));
result = new Item(index++, key2);
put(result);
}
return result;
return newStringishItem(CLASS, value).index;
}
/**
@@ -1247,7 +1222,37 @@ public class ClassWriter extends ClassVisitor {
* item.
*/
public int newMethodType(final String methodDesc) {
return newMethodTypeItem(methodDesc).index;
return newStringishItem(MTYPE, methodDesc).index;
}
/**
* Adds a module reference to the constant pool of the class being
* build. Does nothing if the constant pool already contains a similar item.
* <i>This method is intended for {@link Attribute} sub classes, and is
* normally not needed by class generators or adapters.</i>
*
* @param moduleName
* name of the module.
* @return the index of a new or already existing module reference
* item.
*/
public int newModule(final String moduleName) {
return newStringishItem(MODULE, moduleName).index;
}
/**
* Adds a package reference to the constant pool of the class being
* build. Does nothing if the constant pool already contains a similar item.
* <i>This method is intended for {@link Attribute} sub classes, and is
* normally not needed by class generators or adapters.</i>
*
* @param packageName
* name of the package in its internal form.
* @return the index of a new or already existing module reference
* item.
*/
public int newPackage(final String packageName) {
return newStringishItem(PACKAGE, packageName).index;
}
/**
@@ -1292,38 +1297,6 @@ public class ClassWriter extends ClassVisitor {
return result;
}
/**
* Adds a handle to the constant pool of the class being build. Does nothing
* if the constant pool already contains a similar item. <i>This method is
* intended for {@link Attribute} sub classes, and is normally not needed by
* class generators or adapters.</i>
*
* @param tag
* the kind of 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 field or method owner class.
* @param name
* the name of the field or method.
* @param desc
* the descriptor of the field or method.
* @return the index of a new or already existing method type reference
* item.
*
* @deprecated this method is superseded by
* {@link #newHandle(int, String, String, String, boolean)}.
*/
@Deprecated
public int newHandle(final int tag, final String owner, final String name,
final String desc) {
return newHandle(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE);
}
/**
* Adds a handle to the constant pool of the class being build. Does nothing
* if the constant pool already contains a similar item. <i>This method is
@@ -1628,25 +1601,6 @@ public class ClassWriter extends ClassVisitor {
return result;
}
/**
* Adds a string to the constant pool of the class being build. Does nothing
* if the constant pool already contains a similar item.
*
* @param value
* the String value.
* @return a new or already existing string item.
*/
private Item newString(final String value) {
key2.set(STR, value, null, null);
Item result = get(key2);
if (result == null) {
pool.put12(STR, newUTF8(value));
result = new Item(index++, key2);
put(result);
}
return result;
}
/**
* Adds a name and type to the constant pool of the class being build. Does
* nothing if the constant pool already contains a similar item. <i>This

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

@@ -69,7 +69,7 @@ public abstract class FieldVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
protected final int api;
@@ -84,7 +84,7 @@ public abstract class FieldVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
public FieldVisitor(final int api) {
this(api, null);
@@ -95,15 +95,12 @@ public abstract class FieldVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* 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) {
if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
throw new IllegalArgumentException();
}
this.api = api;
this.fv = fv;
}
@@ -145,9 +142,6 @@ public abstract class FieldVisitor {
*/
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (fv != null) {
return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
}

View File

@@ -147,7 +147,7 @@ final class FieldWriter extends FieldVisitor {
*/
FieldWriter(final ClassWriter cw, final int access, final String name,
final String desc, final String signature, final Object value) {
super(Opcodes.ASM5);
super(Opcodes.ASM6);
if (cw.firstField == null) {
cw.firstField = this;
} else {
@@ -158,7 +158,7 @@ final class FieldWriter extends FieldVisitor {
this.access = access;
this.name = cw.newUTF8(name);
this.desc = cw.newUTF8(desc);
if (ClassReader.SIGNATURES && signature != null) {
if (signature != null) {
this.signature = cw.newUTF8(signature);
}
if (value != null) {
@@ -173,9 +173,6 @@ final class FieldWriter extends FieldVisitor {
@Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
if (!ClassReader.ANNOTATIONS) {
return null;
}
ByteVector bv = new ByteVector();
// write type, and reserve space for values count
bv.putShort(cw.newUTF8(desc)).putShort(0);
@@ -193,9 +190,6 @@ final class FieldWriter extends FieldVisitor {
@Override
public AnnotationVisitor visitTypeAnnotation(final int typeRef,
final TypePath typePath, final String desc, final boolean visible) {
if (!ClassReader.ANNOTATIONS) {
return null;
}
ByteVector bv = new ByteVector();
// write target_type and target_info
AnnotationWriter.putTarget(typeRef, typePath, bv);
@@ -249,23 +243,23 @@ final class FieldWriter extends FieldVisitor {
cw.newUTF8("Deprecated");
size += 6;
}
if (ClassReader.SIGNATURES && signature != 0) {
if (signature != 0) {
cw.newUTF8("Signature");
size += 8;
}
if (ClassReader.ANNOTATIONS && anns != null) {
if (anns != null) {
cw.newUTF8("RuntimeVisibleAnnotations");
size += 8 + anns.getSize();
}
if (ClassReader.ANNOTATIONS && ianns != null) {
if (ianns != null) {
cw.newUTF8("RuntimeInvisibleAnnotations");
size += 8 + ianns.getSize();
}
if (ClassReader.ANNOTATIONS && tanns != null) {
if (tanns != null) {
cw.newUTF8("RuntimeVisibleTypeAnnotations");
size += 8 + tanns.getSize();
}
if (ClassReader.ANNOTATIONS && itanns != null) {
if (itanns != null) {
cw.newUTF8("RuntimeInvisibleTypeAnnotations");
size += 8 + itanns.getSize();
}
@@ -299,19 +293,19 @@ final class FieldWriter extends FieldVisitor {
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
++attributeCount;
}
if (ClassReader.SIGNATURES && signature != 0) {
if (signature != 0) {
++attributeCount;
}
if (ClassReader.ANNOTATIONS && anns != null) {
if (anns != null) {
++attributeCount;
}
if (ClassReader.ANNOTATIONS && ianns != null) {
if (ianns != null) {
++attributeCount;
}
if (ClassReader.ANNOTATIONS && tanns != null) {
if (tanns != null) {
++attributeCount;
}
if (ClassReader.ANNOTATIONS && itanns != null) {
if (itanns != null) {
++attributeCount;
}
if (attrs != null) {
@@ -331,23 +325,23 @@ final class FieldWriter extends FieldVisitor {
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
out.putShort(cw.newUTF8("Deprecated")).putInt(0);
}
if (ClassReader.SIGNATURES && signature != 0) {
if (signature != 0) {
out.putShort(cw.newUTF8("Signature"));
out.putInt(2).putShort(signature);
}
if (ClassReader.ANNOTATIONS && anns != null) {
if (anns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
anns.put(out);
}
if (ClassReader.ANNOTATIONS && ianns != null) {
if (ianns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out);
}
if (ClassReader.ANNOTATIONS && tanns != null) {
if (tanns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
tanns.put(out);
}
if (ClassReader.ANNOTATIONS && itanns != null) {
if (itanns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
itanns.put(out);
}

View File

@@ -63,7 +63,7 @@ package org.redkale.asm;
*
* @author Eric Bruneton
*/
final class Frame {
class Frame {
/*
* Frames are computed in a two steps process: during the visit of each
@@ -192,7 +192,7 @@ final class Frame {
private static final int LOCAL = 0x2000000;
/**
* Kind of the the types that are relative to the stack of an input stack
* Kind of the types that are relative to the stack of an input stack
* map frame. The value of such types is a position relatively to the top of
* this stack.
*/
@@ -525,7 +525,7 @@ final class Frame {
* When the stack map frames are completely computed, this field is the
* actual number of types in {@link #outputStack}.
*/
private int outputStackTop;
int outputStackTop;
/**
* Number of types that are initialized in the basic block.
@@ -549,6 +549,110 @@ final class Frame {
*/
private int[] initializations;
/**
* Sets this frame to the given value.
*
* @param cw
* the ClassWriter to which this label belongs.
* @param nLocal
* the number of local variables.
* @param local
* the local variable types. 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.
* @param stack
* the operand stack types (same format as the "local" array).
*/
final void set(ClassWriter cw, final int nLocal, final Object[] local,
final int nStack, final Object[] stack) {
int i = convert(cw, nLocal, local, inputLocals);
while (i < local.length) {
inputLocals[i++] = TOP;
}
int nStackTop = 0;
for (int j = 0; j < nStack; ++j) {
if (stack[j] == Opcodes.LONG || stack[j] == Opcodes.DOUBLE) {
++nStackTop;
}
}
inputStack = new int[nStack + nStackTop];
convert(cw, nStack, stack, inputStack);
outputStackTop = 0;
initializationCount = 0;
}
/**
* Converts types from the MethodWriter.visitFrame() format to the Frame
* format.
*
* @param cw
* the ClassWriter to which this label belongs.
* @param nInput
* the number of types to convert.
* @param input
* the types to convert. 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 output
* where to store the converted types.
* @return the number of output elements.
*/
private static int convert(ClassWriter cw, int nInput, Object[] input,
int[] output) {
int i = 0;
for (int j = 0; j < nInput; ++j) {
if (input[j] instanceof Integer) {
output[i++] = BASE | ((Integer) input[j]).intValue();
if (input[j] == Opcodes.LONG || input[j] == Opcodes.DOUBLE) {
output[i++] = TOP;
}
} else if (input[j] instanceof String) {
output[i++] = type(cw, Type.getObjectType((String) input[j])
.getDescriptor());
} else {
output[i++] = UNINITIALIZED
| cw.addUninitializedType("",
((Label) input[j]).position);
}
}
return i;
}
/**
* Sets this frame to the value of the given frame. WARNING: after this
* method is called the two frames share the same data structures. It is
* recommended to discard the given frame f to avoid unexpected side
* effects.
*
* @param f
* The new frame value.
*/
final void set(final Frame f) {
inputLocals = f.inputLocals;
inputStack = f.inputStack;
outputLocals = f.outputLocals;
outputStack = f.outputStack;
outputStackTop = f.outputStackTop;
initializationCount = f.initializationCount;
initializations = f.initializations;
}
/**
* Returns the output frame local variable type at the given index.
*
@@ -614,7 +718,7 @@ final class Frame {
}
// pushes the type on the output stack
outputStack[outputStackTop++] = type;
// updates the maximun height reached by the output stack, if needed
// updates the maximum height reached by the output stack, if needed
int top = owner.inputStackTop + outputStackTop;
if (top > owner.outputStackMax) {
owner.outputStackMax = top;
@@ -650,7 +754,7 @@ final class Frame {
* a type descriptor.
* @return the int encoding of the given type.
*/
private static int type(final ClassWriter cw, final String desc) {
static int type(final ClassWriter cw, final String desc) {
String t;
int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
switch (desc.charAt(index)) {
@@ -838,7 +942,7 @@ final class Frame {
* @param maxLocals
* the maximum number of local variables of this method.
*/
void initInputFrame(final ClassWriter cw, final int access,
final void initInputFrame(final ClassWriter cw, final int access,
final Type[] args, final int maxLocals) {
inputLocals = new int[maxLocals];
inputStack = new int[0];
@@ -981,7 +1085,7 @@ final class Frame {
case Opcodes.AALOAD:
pop(1);
t1 = pop();
push(ELEMENT_OF + t1);
push(t1 == NULL ? t1 : ELEMENT_OF + t1);
break;
case Opcodes.ISTORE:
case Opcodes.FSTORE:
@@ -1312,7 +1416,7 @@ final class Frame {
* @return <tt>true</tt> if the input frame of the given label has been
* changed by this operation.
*/
boolean merge(final ClassWriter cw, final Frame frame, final int edge) {
final boolean merge(final ClassWriter cw, final Frame frame, final int edge) {
boolean changed = false;
int i, s, dim, kind, t;

View File

@@ -99,34 +99,6 @@ public final class Handle {
*/
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.
*
* @deprecated this constructor has been superseded
* by {@link #Handle(int, String, String, String, boolean)}.
*/
@Deprecated
public Handle(int tag, String owner, String name, String desc) {
this(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE);
}
/**
* Constructs a new field or method handle.

View File

@@ -80,6 +80,7 @@ final class Item {
* {@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
@@ -239,12 +240,12 @@ final class Item {
this.strVal3 = strVal3;
switch (type) {
case ClassWriter.CLASS:
case ClassWriter.MODULE:
case ClassWriter.PACKAGE:
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;

View File

@@ -139,7 +139,8 @@ public class Label {
/**
* 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 method.
* package you must override the
*
*/
public Object info;
@@ -388,13 +389,12 @@ public class Label {
* 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 to
* @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 need to be replaced with true instructions with
* wider offsets (4 bytes instead of 2). This is done in
* {@link MethodWriter#resizeInstructions}.
* 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.
@@ -453,7 +453,7 @@ public class Label {
* @return the first label of the series to which this label belongs.
*/
Label getFirst() {
return !ClassReader.FRAMES || frame == null ? this : frame.owner;
return frame == null ? this : frame.owner;
}
// ------------------------------------------------------------------------

View File

@@ -32,7 +32,7 @@ public class MethodDebugVisitor {
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

View File

@@ -86,7 +86,7 @@ public abstract class MethodVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
protected final int api;
@@ -101,7 +101,7 @@ public abstract class MethodVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/
public MethodVisitor(final int api) {
this(api, null);
@@ -112,15 +112,12 @@ public abstract class MethodVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* 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) {
if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
throw new IllegalArgumentException();
}
this.api = api;
this.mv = mv;
}
@@ -140,9 +137,6 @@ public abstract class MethodVisitor {
* allowed (see {@link Opcodes}).
*/
public void visitParameter(String name, int access) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (mv != null) {
mv.visitParameter(name, access);
}
@@ -209,9 +203,6 @@ public abstract class MethodVisitor {
*/
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (mv != null) {
return mv.visitTypeAnnotation(typeRef, typePath, desc, visible);
}
@@ -453,34 +444,6 @@ public abstract class MethodVisitor {
}
}
/**
* 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}).
*/
@Deprecated
public void visitMethodInsn(int opcode, String owner, String name,
String desc) {
if (api >= Opcodes.ASM5) {
boolean itf = opcode == Opcodes.INVOKEINTERFACE;
visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc);
}
}
/**
* Visits a method instruction. A method instruction is an instruction that
@@ -502,14 +465,6 @@ public abstract class MethodVisitor {
*/
public void visitMethodInsn(int opcode, String owner, String name,
String desc, boolean itf) {
if (api < Opcodes.ASM5) {
if (itf != (opcode == Opcodes.INVOKEINTERFACE)) {
throw new IllegalArgumentException(
"INVOKESPECIAL/STATIC on interfaces require ASM 5");
}
visitMethodInsn(opcode, owner, name, desc);
return;
}
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc, itf);
}
@@ -723,9 +678,6 @@ public abstract class MethodVisitor {
*/
public AnnotationVisitor visitInsnAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (mv != null) {
return mv.visitInsnAnnotation(typeRef, typePath, desc, visible);
}
@@ -783,9 +735,6 @@ public abstract class MethodVisitor {
*/
public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (mv != null) {
return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible);
}
@@ -854,9 +803,6 @@ public abstract class MethodVisitor {
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
TypePath typePath, Label[] start, Label[] end, int[] index,
String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (mv != null) {
return mv.visitLocalVariableAnnotation(typeRef, typePath, start,
end, index, desc, visible);

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

@@ -1,4 +1,33 @@
/*
* 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.
@@ -41,25 +70,22 @@ package org.redkale.asm;
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
@SuppressWarnings("deprecation") // for Integer(int) constructor
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_1 = 3 << 16 | 45;
int V1_2 = 0 << 16 | 46;
int V1_3 = 0 << 16 | 47;
int V1_4 = 0 << 16 | 48;
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 V1_9 = 0 << 16 | 53;
int V9 = 0 << 16 | 53;
int V10 = 0 << 16 | 54;
// access flags
@@ -70,18 +96,23 @@ public interface Opcodes {
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
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
int ACC_MANDATED = 0x8000; // parameter, module, module *
int ACC_MODULE = 0x8000; // class
// ASM specific pseudo access flags
@@ -148,15 +179,17 @@ public interface Opcodes {
*/
int F_SAME1 = 4;
// For reference comparison purposes, construct new instances
// instead of using valueOf() or autoboxing.
Integer TOP = new Integer(0);
Integer INTEGER = new Integer(1);
Integer FLOAT = new Integer(2);
Integer DOUBLE = new Integer(3);
Integer LONG = new Integer(4);
Integer NULL = new Integer(5);
Integer UNINITIALIZED_THIS = new Integer(6);
// 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)

View File

@@ -406,7 +406,16 @@ public class Type {
*/
public static Type getReturnType(final String methodDescriptor) {
char[] buf = methodDescriptor.toCharArray();
return getType(buf, methodDescriptor.indexOf(')') + 1);
int off = 1;
while (true) {
char car = buf[off++];
if (car == ')') {
return getType(buf, off);
} else if (car == 'L') {
while (buf[off++] != ';') {
}
}
}
}
/**

View File

@@ -1,427 +1,481 @@
/*
* 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.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;
}
}
/*
* 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

@@ -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.getConf(), "apidoc-template.html");
InputStream in = null;
if (doctemplate.isFile() && doctemplate.canRead()) {
in = new FileInputStream(doctemplate);

View File

@@ -61,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
*/
@@ -96,6 +101,11 @@ public final class Application {
*/
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;
@@ -132,6 +142,9 @@ public final class Application {
//进程根目录
private final File home;
//配置文件目录
private final File conf;
//日志
private final Logger logger;
@@ -157,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);
@@ -165,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.conf = new File(confsubpath).getCanonicalFile();
} else {
this.conf = new File(this.home, confsubpath).getCanonicalFile();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -189,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(conf, "logging.properties");
if (logconf.isFile() && logconf.canRead()) {
try {
final String rootpath = root.getCanonicalPath().replace('\\', '/');
@@ -249,8 +269,8 @@ public final class Application {
TransportStrategy strategy = null;
int bufferCapacity = 32 * 1024;
int bufferPoolSize = Runtime.getRuntime().availableProcessors() * 8;
int readTimeoutSecond = TransportFactory.DEFAULT_READTIMEOUTSECOND;
int writeTimeoutSecond = TransportFactory.DEFAULT_WRITETIMEOUTSECOND;
int readTimeoutSeconds = TransportFactory.DEFAULT_READTIMEOUTSECONDS;
int writeTimeoutSeconds = TransportFactory.DEFAULT_WRITETIMEOUTSECONDS;
AtomicLong createBufferCounter = new AtomicLong();
AtomicLong cycleBufferCounter = new AtomicLong();
if (resources != null) {
@@ -260,8 +280,8 @@ public final class Application {
if (transportConf != null) {
//--------------transportBufferPool-----------
bufferCapacity = Math.max(parseLenth(transportConf.getValue("bufferCapacity"), bufferCapacity), 8 * 1024);
readTimeoutSecond = transportConf.getIntValue("readTimeoutSecond", readTimeoutSecond);
writeTimeoutSecond = transportConf.getIntValue("writeTimeoutSecond", writeTimeoutSecond);
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;
@@ -275,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) -> {
@@ -314,8 +334,10 @@ public final class Application {
return true;
});
}
this.sncpTransportFactory = TransportFactory.create(transportExec, transportPool, transportGroup, (SSLContext) null, readTimeoutSecond, writeTimeoutSecond, strategy);
DefaultAnyValue tarnsportConf = DefaultAnyValue.create(TransportFactory.NAME_PINGINTERVAL, System.getProperty("net.transport.pinginterval", "30"));
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);
@@ -341,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 getConf() {
return conf;
}
public long getStartTime() {
return startTime;
}
@@ -354,8 +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");
@@ -363,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.conf, "persistence.xml");
final String homepath = this.home.getCanonicalPath();
final String confpath = this.conf.getCanonicalPath();
if (persist.isFile()) System.setProperty(DataSources.DATASOURCE_CONFPATH, persist.getCanonicalPath());
logger.log(Level.INFO, "APP_JAVA = " + System.getProperty("java.version") + "\r\n" + RESNAME_APP_ADDR + " = " + this.localAddress.getHostAddress() + "\r\n" + RESNAME_APP_HOME + " = " + homepath);
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() ? (homepath + "/conf") : (lib + ";" + homepath + "/conf");
lib = lib.isEmpty() ? confpath : (lib + ";" + confpath);
Server.loadLib(classLoader, logger, lib);
//------------------------------------------------------------------------
@@ -381,13 +425,13 @@ public final class Application {
if (dfloads != null) {
for (String dfload : dfloads.split(";")) {
if (dfload.trim().isEmpty()) continue;
final File df = (dfload.indexOf('/') < 0) ? new File(home, "conf/" + dfload) : new File(dfload);
final File df = (dfload.indexOf('/') < 0) ? new File(conf, "/" + 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)));
}
}
}
@@ -395,6 +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}", homepath);
if (name.startsWith("system.property.")) {
System.setProperty(name.substring("system.property.".length()), value);
} else if (name.startsWith("mimetype.property.")) {
@@ -427,7 +472,8 @@ public final class Application {
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.sncpTransportFactory);
} else if (type == NodeSncpServer.class) {
@@ -502,7 +548,8 @@ public final class Application {
if (listenClass.isEmpty()) continue;
Class clazz = classLoader.loadClass(listenClass);
if (!ApplicationListener.class.isAssignableFrom(clazz)) continue;
ApplicationListener listener = (ApplicationListener) clazz.newInstance();
@SuppressWarnings("unchecked")
ApplicationListener listener = (ApplicationListener) clazz.getDeclaredConstructor().newInstance();
listener.init(config);
this.listeners.add(listener);
}
@@ -512,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.conf, "application.xml");
confFile.renameTo(new File(this.conf, "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();
@@ -594,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)) {
@@ -641,19 +688,21 @@ public final class Application {
runServers(timecd, watchs); //必须在所有服务都启动后再启动WATCH服务
timecd.await();
//if (!singletonrun) signalHandle();
if (!singletonrun) clearPersistData();
//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;
for (File file : cachedir.listFiles()) {
if (file.getName().startsWith("persist-")) file.delete();
}
}
// 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"};
@@ -784,8 +833,15 @@ public final class Application {
public static Application create(final boolean singleton) throws IOException {
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 {

View File

@@ -7,7 +7,7 @@ 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.*;
@@ -30,7 +30,7 @@ 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<>(); //符合条件的结果
@@ -136,10 +136,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 +151,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 +178,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;
@@ -189,9 +202,10 @@ public final class ClassFilter<T> {
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) || ((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);
}
}
}
@@ -347,6 +361,7 @@ public final class ClassFilter<T> {
public void setPrivilegeExcludes(Set<String> privilegeExcludes) {
this.privilegeExcludes = privilegeExcludes == null || privilegeExcludes.isEmpty() ? null : privilegeExcludes;
}
/**
@@ -502,7 +517,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 +526,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 +545,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 +565,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

@@ -241,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");
@@ -266,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) {
}
@@ -274,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) {
}

View File

@@ -9,6 +9,7 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Level;
import javax.annotation.*;
import static org.redkale.boot.Application.RESNAME_SNCP_ADDR;
@@ -56,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");
}
@@ -87,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);
}
@@ -119,8 +124,8 @@ public class NodeHttpServer extends NodeServer {
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);
@@ -136,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);
@@ -172,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 : "";
@@ -213,6 +218,7 @@ public class NodeHttpServer extends NodeServer {
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;
@@ -239,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<>();
@@ -312,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++) {
@@ -336,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

@@ -19,10 +19,9 @@ import javax.annotation.*;
import javax.persistence.Transient;
import static org.redkale.boot.Application.*;
import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.convert.bson.*;
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.*;
@@ -96,6 +95,7 @@ public abstract class NodeServer {
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) {
@@ -149,7 +149,7 @@ public abstract class NodeServer {
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();
@@ -198,7 +198,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);
@@ -221,7 +221,7 @@ 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;
@@ -231,7 +231,14 @@ public abstract class NodeServer {
boolean needinit = true;
if (sourceConf != null) {
final Class sourceType = serverClassLoader.loadClass(sourceConf.getValue("value"));
if (DataSource.class.isAssignableFrom(sourceType)) { // DataSource
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();
@@ -271,8 +278,9 @@ public abstract class NodeServer {
}
}, 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;
@@ -317,15 +325,52 @@ 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;
@@ -340,7 +385,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);
@@ -358,6 +402,11 @@ 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
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) { //本地模式
@@ -365,8 +414,6 @@ public abstract class NodeServer {
} else {
service = Sncp.createRemoteService(serverClassLoader, resourceName, serviceImplClass, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
}
if (SncpClient.parseMethod(serviceImplClass).isEmpty() && serviceImplClass.getAnnotation(Priority.class) == null) return; //class没有可用的方法且没有标记启动优先级的 通常为BaseService
final Class restype = Sncp.getResourceType(service);
if (rf.find(resourceName, restype) == null) {
regFactory.register(resourceName, restype, service);
@@ -430,24 +477,19 @@ public abstract class NodeServer {
localServices.addAll(swlist);
//this.loadPersistData();
final List<String> slist = sb == null ? null : new CopyOnWriteArrayList<>();
CountDownLatch clds = new CountDownLatch(localServices.size());
localServices.stream().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();
}
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行)
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());
}
@@ -457,125 +499,6 @@ public abstract class NodeServer {
maxClassNameLength = Math.max(maxClassNameLength, Sncp.getResourceType(y).getName().length() + 1);
}
//尚未完整实现, 先屏蔽, 单个Service在多个Server中存在的情况下进行缓存的方案还未考虑清楚
@SuppressWarnings("unchecked")
private void loadPersistData() throws Exception {
File home = application.getHome();
if (home == null || !home.isDirectory()) return;
File cachedir = new File(home, "cache");
if (!cachedir.isDirectory()) return;
int port = this.server.getSocketAddress().getPort();
final String prefix = "persist-" + port + "-";
final BsonConvert convert = BsonFactory.create().skipAllIgnore(true).getConvert();
synchronized (this.application) {
for (final File file : cachedir.listFiles((dir, name) -> name.startsWith(prefix))) {
if (!file.getName().endsWith(".bat")) continue;
String classAndResname = file.getName().substring(prefix.length(), file.getName().length() - 4); //去掉尾部的.bat
int pos = classAndResname.indexOf('-');
String servtype = pos > 0 ? classAndResname.substring(0, pos) : classAndResname;
String resname = pos > 0 ? classAndResname.substring(pos + 1) : "";
FileInputStream in = new FileInputStream(file);
ByteArrayOutputStream out = new ByteArrayOutputStream();
int b;
while ((b = in.read()) != '\n') out.write(b);
final String[] fieldNames = out.toString().split(",");
int timeout = (int) ((System.currentTimeMillis() - file.lastModified()) / 1000);
for (final Service service : this.localServices) {
if (!servtype.equals(Sncp.getResourceType(service).getName())) continue;
if (!resname.equals(Sncp.getResourceName(service))) continue;
for (final String fieldName : fieldNames) {
Field field = null;
Class clzz = service.getClass();
do {
try {
field = clzz.getDeclaredField(fieldName);
break;
} catch (Exception e) {
}
} while ((clzz = clzz.getSuperclass()) != Object.class);
field.setAccessible(true);
Object val = convert.convertFrom(field.getGenericType(), in);
Persist persist = field.getAnnotation(Persist.class);
if (persist.timeout() == 0 || persist.timeout() >= timeout) {
if (Modifier.isFinal(field.getModifiers())) {
if (Map.class.isAssignableFrom(field.getType())) {
((Map) field.get(service)).putAll((Map) val);
} else if (Collection.class.isAssignableFrom(field.getType())) {
((Collection) field.get(service)).addAll((Collection) val);
}
} else {
field.set(service, val);
}
}
if (in.read() != '\n') logger.log(Level.SEVERE, servtype + "'s [" + resname + "] load value error");
}
}
in.close();
}
}
}
//尚未完整实现, 先屏蔽
@SuppressWarnings("unchecked")
private void savePersistData() throws IOException {
File home = application.getHome();
if (home == null || !home.isDirectory()) return;
File cachedir = new File(home, "cache");
int port = this.server.getSocketAddress().getPort();
final String prefix = "persist-" + port + "-";
final BsonConvert convert = BsonFactory.create().skipAllIgnore(true).getConvert();
for (final Service service : this.localServices) {
Class clzz = service.getClass();
final Set<String> fieldNameSet = new HashSet<>();
final List<Field> fields = new ArrayList<>();
final StringBuilder sb = new StringBuilder();
do {
for (Field field : clzz.getDeclaredFields()) {
if (field.getAnnotation(Persist.class) == null) continue;
if (fieldNameSet.contains(field.getName())) continue;
if (Modifier.isStatic(field.getModifiers())) throw new RuntimeException(field + " cannot static on @" + Persist.class.getName() + " in " + clzz.getName());
if (Modifier.isFinal(field.getModifiers()) && !Map.class.isAssignableFrom(field.getType()) && !Collection.class.isAssignableFrom(field.getType())) {
throw new RuntimeException(field + " cannot final on @" + Persist.class.getName() + " in " + clzz.getName());
}
fieldNameSet.add(field.getName());
field.setAccessible(true);
try {
if (field.get(service) == null) continue;
} catch (Exception e) {
logger.log(Level.SEVERE, field + " get value error", e);
continue;
}
fields.add(field);
if (sb.length() > 0) sb.append(',');
sb.append(field.getName());
}
} while ((clzz = clzz.getSuperclass()) != Object.class);
if (fields.isEmpty()) continue; //没有数据需要缓存
// synchronized (this.application.localServices) {
// if (this.application.localServices.contains(service)) continue;
// this.application.localServices.add(service);
// }
if (!cachedir.isDirectory()) cachedir.mkdirs();
String resname = Sncp.getResourceName(service);
FileOutputStream out = new FileOutputStream(new File(cachedir, prefix + Sncp.getResourceType(service).getName() + (resname.isEmpty() ? "" : ("-" + resname)) + ".bat"));
out.write(sb.toString().getBytes());
out.write('\n');
for (Field field : fields) {
Object val = null;
try {
val = field.get(service);
} catch (Exception e) {
logger.log(Level.SEVERE, field + " save value error", e);
}
convert.convertTo(out, field.getGenericType(), val);
out.write('\n');
}
out.close();
}
}
protected abstract ClassFilter<Filter> createFilterClassFilter();
protected abstract ClassFilter<Servlet> createServletClassFilter();
@@ -708,9 +631,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

@@ -93,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);

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,13 @@
*/
package org.redkale.boot.watch;
import org.redkale.net.http.RestService;
import java.util.*;
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 +20,66 @@ 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;
@Resource
protected Application application;
@RestMapping(name = "info", comment = "单个Server信息查询")
public RetResult info(@RestParam(name = "#port:") int port) {
NodeServer node = null;
for (NodeServer ns : application.getNodeServers()) {
if (ns.getServer().getSocketAddress().getPort() == port) {
node = ns;
break;
}
}
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);
}
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,173 @@ 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(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
//待开发
return RetResult.success();
}
@RestMapping(name = "reload", auth = false, comment = "重新加载Service")
public RetResult reloadService(String name, String type) {
//待开发
return RetResult.success();
}
@RestMapping(name = "stop", auth = false, comment = "动态停止Service")
public RetResult stopService(String name, String type) {
//待开发
return RetResult.success();
}
@RestMapping(name = "find", auth = false, comment = "查找Service")
public RetResult find(String name, 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,10 +5,15 @@
*/
package org.redkale.boot.watch;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;
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.*;
/**
*
@@ -17,10 +22,58 @@ import org.redkale.net.http.RestService;
@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
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 = "配置") final Properties properties) throws IOException {
if (name == null) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param (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");
}
}
}

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

@@ -42,16 +42,17 @@ public final class AnyEncoder<T> implements Encodeable<Writer, T> {
out.writeNull();
} else {
int count = values.length - values.length % 2;
out.writeMapB(count / 2);
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);
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();

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;
private boolean inited = false;
protected 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;
@@ -62,8 +62,17 @@ 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) {
int len = in.readArrayB(member, decoder);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, decoder);
len = Reader.SIGN_NOLENGTH;
}
if (this.decoder == null) {
if (!this.inited) {
synchronized (lock) {
@@ -77,9 +86,14 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
}
final Decodeable<Reader, T> localdecoder = this.decoder;
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, first));
first = false;
}
} else {
for (int i = 0; i < len; i++) {
@@ -91,6 +105,18 @@ 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 Reader getItemReader(Reader in, DeMember member, boolean first) {
return in;
}
protected T readMemberValue(Reader in, DeMember member, boolean first) {
return this.decoder.convertFrom(in);
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.decoder + "}";
@@ -101,4 +127,12 @@ public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
return type;
}
public Type getComponentType() {
return componentType;
}
public Decodeable<Reader, T> getDecoder() {
return decoder;
}
}

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> encoder;
private boolean inited = false;
protected 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;
@@ -57,12 +57,16 @@ 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, encoder, value);
out.writeArrayE();
return;
}
@@ -77,17 +81,22 @@ 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, encoder, 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)) ? encoder : 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 + "}";
@@ -97,4 +106,13 @@ public final class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
public Type getType() {
return type;
}
public Type getComponentType() {
return componentType;
}
public Encodeable<Writer, Object> getEncoder() {
return encoder;
}
}

View File

@@ -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;
private boolean inited = false;
protected 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;
@@ -44,9 +44,9 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
this.creator = factory.loadCreator((Class) pt.getRawType());
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
} else if(factory.isReversible()){
} 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);
} else {
@@ -62,8 +62,17 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
@Override
public Collection<T> convertFrom(Reader in) {
final int len = in.readArrayB();
return convertFrom(in, null);
}
public Collection<T> convertFrom(Reader in, DeMember member) {
int len = in.readArrayB(member, decoder);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, decoder);
len = Reader.SIGN_NOLENGTH;
}
if (this.decoder == null) {
if (!this.inited) {
synchronized (lock) {
@@ -77,9 +86,14 @@ public final class CollectionDecoder<T> implements Decodeable<Reader, Collection
}
final Decodeable<Reader, T> localdecoder = this.decoder;
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, first));
first = false;
}
} else {
for (int i = 0; i < len; i++) {
@@ -90,9 +104,29 @@ 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 Reader getItemReader(Reader in, DeMember member, boolean first) {
return in;
}
protected T readMemberValue(Reader in, DeMember member, boolean first) {
return this.decoder.convertFrom(in);
}
@Override
public Type getType() {
return type;
}
public Type getComponentType() {
return componentType;
}
public Decodeable<Reader, T> getDecoder() {
return decoder;
}
}

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> encoder;
private boolean inited = false;
protected 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;
@@ -52,12 +52,16 @@ 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, encoder, value);
out.writeArrayE();
return;
}
@@ -72,18 +76,28 @@ 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(), encoder, 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) {
encoder.convertTo(out, value);
}
@Override
public Type getType() {
return type;
}
public Encodeable<Writer, Object> getEncoder() {
return encoder;
}
}

View File

@@ -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) {
@@ -136,10 +141,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;
}
@@ -171,12 +222,19 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
public ConvertColumnEntry findRef(AccessibleObject element) {
if (element == null) return null;
ConvertColumnEntry en = this.columnEntrys.get(element);
if (en != null) return en;
Set<String> onlyColumns = null;
if (element instanceof Method) {
onlyColumns = ignoreAlls.get(((Method) element).getDeclaringClass());
} else if (element instanceof Field) {
onlyColumns = ignoreAlls.get(((Field) element).getDeclaringClass());
}
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;
String fieldName = readGetSetFieldName(method);
fieldName = readGetSetFieldName(method);
if (fieldName != null) {
try {
ccs = method.getDeclaringClass().getDeclaredField(fieldName).getAnnotationsByType(ConvertColumn.class);
@@ -184,8 +242,22 @@ 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)) {
if (onlyColumns != null && fieldName != null) {
String realName = ref.name().isEmpty() ? fieldName : ref.name();
if (!onlyColumns.contains(realName)) return new ConvertColumnEntry(realName, true);
}
ConvertColumnEntry entry = new ConvertColumnEntry(ref);
if (skipAllIgnore) {
entry.setIgnore(false);
@@ -318,6 +390,22 @@ 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 register(final Class type, boolean ignore, String... columns) {
for (String column : columns) {
register(type, column, new ConvertColumnEntry(column, ignore));
@@ -409,6 +497,29 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
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) {
Decodeable<R, E> rs = (Decodeable<R, E>) decoders.get(type);
if (rs != null) return rs;
@@ -424,7 +535,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;
@@ -456,8 +567,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);
}
@@ -478,19 +588,19 @@ 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
@@ -510,7 +620,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;
@@ -525,7 +635,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;
@@ -543,8 +653,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);
}
@@ -565,15 +674,15 @@ 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) {
@@ -594,7 +703,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

@@ -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

@@ -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 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];
@@ -69,6 +76,10 @@ public final class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
@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) {
@@ -80,31 +91,74 @@ public final class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
}
}
}
final int len = in.readMapB();
int len = in.readMapB(member, this.keyDecoder);
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;
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, first);
entryReader.readBlank();
V value = readValueMember(entryReader, member, 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, first);
in.readBlank();
V value = valueDecoder.convertFrom(in);
V value = readValueMember(in, member, 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 Reader getEntryReader(Reader in, DeMember member, boolean first) {
return in;
}
protected K readKeyMember(Reader in, DeMember member, boolean first) {
return keyDecoder.convertFrom(in);
}
protected V readValueMember(Reader in, DeMember member, boolean first) {
return valueDecoder.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,17 +20,17 @@ 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> valencoder;
private boolean inited = false;
protected 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;
@@ -53,6 +53,10 @@ 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();
@@ -70,20 +74,34 @@ 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) valencoder, 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();
valencoder.convertTo(out, value);
}
@Override
public Type getType() {
return type;
}
public Encodeable<Writer, K> getKeyencoder() {
return keyencoder;
}
public Encodeable<Writer, V> getValencoder() {
return valencoder;
}
}

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;
@@ -33,13 +31,13 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
protected DeMember<R, T, ?>[] creatorConstructorMembers = new DeMember[0];
protected DeMember<R, T, ?>[] members;
protected DeMember[] members;
protected ConvertFactory factory;
private boolean inited = false;
protected 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;
@@ -86,7 +84,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
this.creator = factory.loadCreator(clazz);
if (this.creator == null) throw new ConvertException("Cannot create a creator for " + clazz);
}
final Set<DeMember> list = new HashSet();
final Set<DeMember> list = new LinkedHashSet();
final String[] cps = ObjectEncoder.findConstructorProperties(this.creator);
try {
ConvertColumnEntry ref;
@@ -95,8 +93,12 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
if (factory.isConvertDisabled(field)) continue;
ref = factory.findRef(field);
if (ref != null && ref.ignore()) continue;
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), 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);
}
@@ -120,8 +122,13 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
}
ref = factory.findRef(method);
if (ref != null && ref.ignore()) continue;
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericParameterTypes()[0], this.type), 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);
}
@@ -156,7 +163,20 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, 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;
@@ -190,7 +210,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);
@@ -210,14 +230,16 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
}
if (this.creatorConstructorMembers == null) { //空构造函数
final T result = this.creator.create();
while (in.hasNext()) {
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;
@@ -226,13 +248,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]) {
@@ -242,7 +265,9 @@ 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);
final T result = this.creator.create(constructorParams);
@@ -253,11 +278,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,9 +32,9 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
protected ConvertFactory factory;
private boolean inited = false;
protected boolean inited = false;
private final Object lock = new Object();
protected final Object lock = new Object();
protected ObjectEncoder(Type type) {
this.type = type;
@@ -61,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 {
@@ -77,8 +77,12 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
if (factory.isConvertDisabled(field)) continue;
ref = factory.findRef(field);
if (ref != null && ref.ignore()) continue;
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), 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);
}
@@ -102,13 +106,30 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
}
ref = factory.findRef(method);
if (ref != null && ref.ignore()) continue;
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericReturnType(), this.type), 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);
@@ -122,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;
@@ -136,24 +157,29 @@ 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) {
for (EnMember member : members) {
out.writeObjectField(member, value);
}
}
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) + '}';

View File

@@ -34,6 +34,7 @@ public class OptionalCoder<R extends Reader, W extends Writer, T> extends Simple
private final Object lock = new Object();
@SuppressWarnings("unchecked")
public OptionalCoder(final ConvertFactory factory, final Type type) {
this.type = type;
try {

View File

@@ -22,12 +22,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);
/**
* 跳过值(不包含值前面的字段)
@@ -61,9 +95,12 @@ public abstract class Reader {
/**
* 读取数组的开头并返回数组的长度
*
* @param member DeMember
* @param decoder Decodeable
*
* @return 返回数组的长度
*/
public abstract int readArrayB();
public abstract int readArrayB(DeMember member, Decodeable decoder);
/**
* 读取数组的尾端
@@ -74,9 +111,12 @@ public abstract class Reader {
/**
* 读取map的开头并返回map的size
*
* @param member DeMember
* @param keydecoder Decodeable
*
* @return 返回map的size
*/
public abstract int readMapB();
public abstract int readMapB(DeMember member, Decodeable keydecoder);
/**
* 读取数组的尾端
@@ -107,6 +147,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;
private boolean inited = false;
protected 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;
@@ -58,8 +58,17 @@ 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) {
int len = in.readArrayB(member, this.decoder);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, this.decoder);
len = Reader.SIGN_NOLENGTH;
}
if (this.decoder == null) {
if (!this.inited) {
synchronized (lock) {
@@ -73,9 +82,14 @@ public final class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
}
final Decodeable<Reader, T> localdecoder = this.decoder;
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, first));
first = false;
}
} else {
for (int i = 0; i < len; i++) {
@@ -86,9 +100,29 @@ 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 Reader getItemReader(Reader in, DeMember member, boolean first) {
return in;
}
protected T readMemberValue(Reader in, DeMember member, boolean first) {
return this.decoder.convertFrom(in);
}
@Override
public Type getType() {
return type;
}
public Type getComponentType() {
return componentType;
}
public Decodeable<Reader, T> getDecoder() {
return decoder;
}
}

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> encoder;
private boolean inited = false;
protected 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;
@@ -52,13 +52,17 @@ 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, encoder, array);
out.writeArrayE();
return;
}
@@ -73,18 +77,28 @@ 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, encoder, 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) {
encoder.convertTo(out, value);
}
@Override
public Type getType() {
return type;
}
public Encodeable<Writer, Object> getEncoder() {
return encoder;
}
}

View File

@@ -5,7 +5,7 @@
*/
package org.redkale.convert;
import org.redkale.util.Attribute;
import java.lang.reflect.*;
/**
* 序列化的数据输出流
@@ -20,6 +20,33 @@ public abstract class Writer {
//当前对象输出字段名之前是否需要分隔符, JSON字段间的分隔符为,逗号
protected boolean comma;
//convertTo时是否以指定Type的ObjectEncoder进行处理
protected Type specify;
/**
* 设置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;
}
}
/**
* 返回specify
*
* @return int
*/
public Type specify() {
return this.specify;
}
/**
* 当tiny=true时 字符串为空、boolean为false的字段值都会被跳过 不会输出。
*
@@ -51,9 +78,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,7 +104,7 @@ public abstract class Writer {
* @param obj 写入的对象
*/
@SuppressWarnings("unchecked")
public final void writeObjectField(final EnMember member, Object obj) {
public void writeObjectField(final EnMember member, Object obj) {
Object value = member.attribute.get(obj);
if (value == null) return;
if (tiny()) {
@@ -84,7 +114,7 @@ public abstract class Writer {
if (!((Boolean) value)) return;
}
}
this.writeFieldName(member.attribute);
this.writeFieldName(member);
member.encoder.convertTo(this, value);
this.comma = true;
}
@@ -99,9 +129,13 @@ public abstract class Writer {
/**
* 输出一个数组前的操作
*
* @param size 数组长度
* @param size 数组长度
* @param encoder Encodeable
* @param obj 对象
*
* @return 返回-1表示还没有写入对象内容大于-1表示已写入对象内容返回对象内容大小
*/
public abstract void writeArrayB(int size);
public abstract int writeArrayB(int size, Encodeable<Writer, Object> encoder, Object obj);
/**
* 输出数组元素间的间隔符
@@ -118,9 +152,14 @@ public abstract class Writer {
/**
* 输出一个Map前的操作
*
* @param size map大小
* @param size map大小
* @param keyEncoder Encodeable
* @param valueEncoder Encodeable
* @param obj 对象
*
* @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 +176,9 @@ public abstract class Writer {
/**
* 输出一个字段名
*
* @param attribute 字段的Attribute对象
* @param member 字段的EnMember对象
*/
public abstract void writeFieldName(Attribute attribute);
public abstract void writeFieldName(EnMember member);
/**
* 写入一个boolean值
@@ -155,6 +194,13 @@ public abstract class Writer {
*/
public abstract void writeByte(byte value);
/**
* 写入byte[]
*
* @param values byte[]
*/
public abstract void writeByteArray(byte[] values);
/**
* 写入一个char值
*

View File

@@ -51,10 +51,12 @@ public class BsonByteBufferReader extends BsonReader {
/**
* 判断下一个非空白字节是否为[
*
* @param member DeMember
* @param decoder Decodeable
* @return 数组长度或 SIGN_NULL
*/
@Override
public final int readArrayB() {
public final int readArrayB(DeMember member, Decodeable decoder) {
short bt = readShort();
if (bt == Reader.SIGN_NULL) return bt;
short lt = readShort();

View File

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

View File

@@ -84,4 +84,9 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
return true;
}
@Override
public boolean isFieldSort() {
return true;
}
}

View File

@@ -171,8 +171,8 @@ public class BsonReader extends Reader {
}
@Override
public final int readMapB() {
return readArrayB();
public final int readMapB(DeMember member, Decodeable keydecoder) {
return readArrayB(member, keydecoder);
}
@Override
@@ -185,7 +185,7 @@ public class BsonReader extends Reader {
* @return 数组长度或SIGN_NULL
*/
@Override
public int readArrayB() {
public int readArrayB(DeMember member, Decodeable decoder) {
short bt = readShort();
if (bt == Reader.SIGN_NULL) return bt;
return (bt & 0xffff) << 16 | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
@@ -202,13 +202,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)
@@ -248,6 +261,41 @@ public class BsonReader extends Reader {
return content[++this.position];
}
@Override
public final byte[] readByteArray() {
int len = readArrayB(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]));

View File

@@ -98,6 +98,7 @@ public class BsonWriter extends Writer {
protected boolean recycle() {
this.count = 0;
this.specify = null;
if (this.content.length > defaultSize) {
this.content = new byte[defaultSize];
}
@@ -124,6 +125,22 @@ public class BsonWriter extends Writer {
writeTo(value);
}
@Override
public final void writeByteArray(byte[] values) {
if (values == null) {
writeNull();
return;
}
writeArrayB(values.length, null, values);
boolean flag = false;
for (byte v : values) {
if (flag) writeArrayMark();
writeByte(v);
flag = true;
}
writeArrayE();
}
@Override
public final void writeChar(final char value) {
writeTo((byte) ((value & 0xFF00) >> 8), (byte) (value & 0xFF));
@@ -166,10 +183,11 @@ public class BsonWriter extends Writer {
}
@Override
public final void writeObjectB(Object obj) {
public final int writeObjectB(Object obj) {
super.writeObjectB(obj);
writeSmallString("");
writeShort(BsonReader.SIGN_OBJECTB);
return -1;
}
@Override
@@ -179,7 +197,8 @@ public class BsonWriter extends Writer {
}
@Override
public final void writeFieldName(Attribute attribute) {
public final void writeFieldName(EnMember member) {
Attribute attribute = member.getAttribute();
writeByte(BsonReader.SIGN_HASNEXT);
writeSmallString(attribute.field());
byte typeval = 127; //字段的类型值
@@ -266,8 +285,9 @@ public class BsonWriter extends Writer {
}
@Override
public final void writeArrayB(int size) {
public final int writeArrayB(int size, Encodeable<Writer, Object> encoder, Object obj) {
writeInt(size);
return -1;
}
@Override
@@ -279,8 +299,9 @@ public class BsonWriter extends Writer {
}
@Override
public void writeMapB(int size) {
writeArrayB(size);
public int writeMapB(int size, Encodeable<Writer, Object> keyEncoder, Encodeable<Writer, Object> valueEncoder, Object obj) {
writeArrayB(size, valueEncoder, obj);
return -1;
}
@Override

View File

@@ -25,6 +25,7 @@ public final class BigIntegerSimpledCoder<R extends Reader, W extends Writer> ex
public static final BigIntegerSimpledCoder instance = new BigIntegerSimpledCoder();
@Override
@SuppressWarnings("unchecked")
public void convertTo(W out, BigInteger value) {
if (value == null) {
out.writeNull();
@@ -34,6 +35,7 @@ public final class BigIntegerSimpledCoder<R extends Reader, W extends Writer> ex
}
@Override
@SuppressWarnings("unchecked")
public BigInteger convertFrom(R in) {
byte[] bytes = ByteArraySimpledCoder.instance.convertFrom(in);
return bytes == null ? null : new BigInteger(bytes);

View File

@@ -29,24 +29,31 @@ public final class BoolArraySimpledCoder<R extends Reader, W extends Writer> ext
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (boolean v : values) {
if (flag) out.writeArrayMark();
out.writeBoolean(v);
flag = true;
if (out.writeArrayB(values.length, BoolSimpledCoder.instance, values) < 0) {
boolean flag = false;
for (boolean v : values) {
if (flag) out.writeArrayMark();
out.writeBoolean(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public boolean[] convertFrom(R in) {
int len = in.readArrayB();
int len = in.readArrayB(null, BoolSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, BoolSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
boolean[] data = new boolean[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
boolean[] newdata = new boolean[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);

View File

@@ -11,7 +11,7 @@ import org.redkale.convert.Writer;
/**
* byte[] 的SimpledCoder实现
*
*
* <p>
* 详情见: https://redkale.org
*
@@ -25,47 +25,12 @@ public final class ByteArraySimpledCoder<R extends Reader, W extends Writer> ext
@Override
public void convertTo(W out, byte[] values) {
if (values == null) {
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (byte v : values) {
if (flag) out.writeArrayMark();
out.writeByte(v);
flag = true;
}
out.writeArrayE();
out.writeByteArray(values);
}
@Override
public byte[] convertFrom(R in) {
int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
byte[] data = new byte[8];
while (in.hasNext()) {
if (size >= data.length) {
byte[] newdata = new byte[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
data = newdata;
}
data[size++] = in.readByte();
}
in.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] = in.readByte();
}
in.readArrayE();
return values;
}
return in.readByteArray();
}
}

View File

@@ -30,24 +30,31 @@ public final class ByteBufferSimpledCoder<R extends Reader, W extends Writer> ex
out.writeNull();
return;
}
out.writeArrayB(value.remaining());
boolean flag = false;
for (byte v : value.array()) {
if (flag) out.writeArrayMark();
out.writeByte(v);
flag = true;
if (out.writeArrayB(value.remaining(), ByteSimpledCoder.instance, value) < 0) {
boolean flag = false;
for (byte v : value.array()) {
if (flag) out.writeArrayMark();
out.writeByte(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public ByteBuffer convertFrom(R in) {
int len = in.readArrayB();
int len = in.readArrayB(null, ByteSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, ByteSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
byte[] data = new byte[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
byte[] newdata = new byte[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);

View File

@@ -12,7 +12,9 @@ import org.redkale.convert.Writer;
/**
* char[] 的SimpledCoder实现
*
* <p> 详情见: https://redkale.org
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
@@ -27,24 +29,31 @@ public final class CharArraySimpledCoder<R extends Reader, W extends Writer> ext
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (char v : values) {
if (flag) out.writeArrayMark();
out.writeChar(v);
flag = true;
if (out.writeArrayB(values.length, CharSimpledCoder.instance, values) < 0) {
boolean flag = false;
for (char v : values) {
if (flag) out.writeArrayMark();
out.writeChar(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public char[] convertFrom(R in) {
int len = in.readArrayB();
int len = in.readArrayB(null, CharSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, CharSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
char[] data = new char[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
char[] newdata = new char[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);

View File

@@ -27,6 +27,7 @@ public final class DLongSimpledCoder<R extends Reader, W extends Writer> extends
public static final DLongSimpledCoder instance = new DLongSimpledCoder();
@Override
@SuppressWarnings("unchecked")
public void convertTo(final W out, final DLong value) {
if (value == null) {
out.writeNull();
@@ -36,6 +37,7 @@ public final class DLongSimpledCoder<R extends Reader, W extends Writer> extends
}
@Override
@SuppressWarnings("unchecked")
public DLong convertFrom(R in) {
byte[] bs = bsSimpledCoder.convertFrom(in);
if (bs == null) return null;

View File

@@ -30,24 +30,31 @@ public final class DoubleArraySimpledCoder<R extends Reader, W extends Writer> e
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (double v : values) {
if (flag) out.writeArrayMark();
out.writeDouble(v);
flag = true;
if (out.writeArrayB(values.length, DoubleSimpledCoder.instance, values) < 0) {
boolean flag = false;
for (double v : values) {
if (flag) out.writeArrayMark();
out.writeDouble(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public double[] convertFrom(R in) {
int len = in.readArrayB();
int len = in.readArrayB(null, DoubleSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, DoubleSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
double[] data = new double[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
double[] newdata = new double[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
@@ -74,6 +81,7 @@ public final class DoubleArraySimpledCoder<R extends Reader, W extends Writer> e
public static final DoubleStreamSimpledCoder instance = new DoubleStreamSimpledCoder();
@Override
@SuppressWarnings("unchecked")
public void convertTo(W out, DoubleStream values) {
if (values == null) {
out.writeNull();
@@ -83,6 +91,7 @@ public final class DoubleArraySimpledCoder<R extends Reader, W extends Writer> e
}
@Override
@SuppressWarnings("unchecked")
public DoubleStream convertFrom(R in) {
double[] value = DoubleArraySimpledCoder.instance.convertFrom(in);
return value == null ? null : DoubleStream.of(value);

View File

@@ -45,4 +45,8 @@ public final class EnumSimpledCoder<R extends Reader, W extends Writer, E extend
return (E) Enum.valueOf(type, value);
}
@Override
public Class<E> getType() {
return type;
}
}

View File

@@ -12,7 +12,9 @@ import org.redkale.convert.Writer;
/**
* float[] 的SimpledCoder实现
*
* <p> 详情见: https://redkale.org
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
@@ -27,24 +29,31 @@ public final class FloatArraySimpledCoder<R extends Reader, W extends Writer> ex
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (float v : values) {
if (flag) out.writeArrayMark();
out.writeFloat(v);
flag = true;
if (out.writeArrayB(values.length, FloatSimpledCoder.instance, values) < 0) {
boolean flag = false;
for (float v : values) {
if (flag) out.writeArrayMark();
out.writeFloat(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public float[] convertFrom(R in) {
int len = in.readArrayB();
int len = in.readArrayB(null, FloatSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, FloatSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
float[] data = new float[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
float[] newdata = new float[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);

View File

@@ -30,24 +30,31 @@ public final class IntArraySimpledCoder<R extends Reader, W extends Writer> exte
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (int v : values) {
if (flag) out.writeArrayMark();
out.writeInt(v);
flag = true;
if (out.writeArrayB(values.length, IntSimpledCoder.instance, values) < 0) {
boolean flag = false;
for (int v : values) {
if (flag) out.writeArrayMark();
out.writeInt(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public int[] convertFrom(R in) {
int len = in.readArrayB();
int len = in.readArrayB(null, IntSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, IntSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
int[] data = new int[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
int[] newdata = new int[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
@@ -74,6 +81,7 @@ public final class IntArraySimpledCoder<R extends Reader, W extends Writer> exte
public static final IntStreamSimpledCoder instance = new IntStreamSimpledCoder();
@Override
@SuppressWarnings("unchecked")
public void convertTo(W out, IntStream values) {
if (values == null) {
out.writeNull();
@@ -83,6 +91,7 @@ public final class IntArraySimpledCoder<R extends Reader, W extends Writer> exte
}
@Override
@SuppressWarnings("unchecked")
public IntStream convertFrom(R in) {
int[] value = IntArraySimpledCoder.instance.convertFrom(in);
return value == null ? null : IntStream.of(value);

View File

@@ -30,24 +30,31 @@ public final class LongArraySimpledCoder<R extends Reader, W extends Writer> ext
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (long v : values) {
if (flag) out.writeArrayMark();
out.writeLong(v);
flag = true;
if (out.writeArrayB(values.length, LongSimpledCoder.instance, values) < 0) {
boolean flag = false;
for (long v : values) {
if (flag) out.writeArrayMark();
out.writeLong(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public long[] convertFrom(R in) {
int len = in.readArrayB();
int len = in.readArrayB(null, LongSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, LongSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
long[] data = new long[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
long[] newdata = new long[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
@@ -74,6 +81,7 @@ public final class LongArraySimpledCoder<R extends Reader, W extends Writer> ext
public static final LongStreamSimpledCoder instance = new LongStreamSimpledCoder();
@Override
@SuppressWarnings("unchecked")
public void convertTo(W out, LongStream values) {
if (values == null) {
out.writeNull();
@@ -83,6 +91,7 @@ public final class LongArraySimpledCoder<R extends Reader, W extends Writer> ext
}
@Override
@SuppressWarnings("unchecked")
public LongStream convertFrom(R in) {
long[] value = LongArraySimpledCoder.instance.convertFrom(in);
return value == null ? null : LongStream.of(value);

View File

@@ -12,7 +12,9 @@ import org.redkale.convert.Writer;
/**
* short[] 的SimpledCoder实现
*
* <p> 详情见: https://redkale.org
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
@@ -27,24 +29,31 @@ public final class ShortArraySimpledCoder<R extends Reader, W extends Writer> ex
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (short v : values) {
if (flag) out.writeArrayMark();
out.writeShort(v);
flag = true;
if (out.writeArrayB(values.length, ShortSimpledCoder.instance, values) < 0) {
boolean flag = false;
for (short v : values) {
if (flag) out.writeArrayMark();
out.writeShort(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public short[] convertFrom(R in) {
int len = in.readArrayB();
int len = in.readArrayB(null, ShortSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, ShortSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
short[] data = new short[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
short[] newdata = new short[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);

View File

@@ -5,14 +5,14 @@
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
import org.redkale.convert.*;
/**
* String[] 的SimpledCoder实现
*
* <p> 详情见: https://redkale.org
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
@@ -27,24 +27,35 @@ public final class StringArraySimpledCoder<R extends Reader, W extends Writer> e
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (String v : values) {
if (flag) out.writeArrayMark();
out.writeString(v);
flag = true;
if (out.writeArrayB(values.length, StringSimpledCoder.instance, values) < 0) {
boolean flag = false;
for (String v : values) {
if (flag) out.writeArrayMark();
out.writeString(v);
flag = true;
}
}
out.writeArrayE();
}
@Override
public String[] convertFrom(R in) {
int len = in.readArrayB();
return convertFrom(in, null);
}
public String[] convertFrom(R in, DeMember member) {
int len = in.readArrayB(member, StringSimpledCoder.instance);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(null, StringSimpledCoder.instance);
len = Reader.SIGN_NOLENGTH;
}
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
String[] data = new String[8];
while (in.hasNext()) {
int startPosition = in.position();
while (in.hasNext(startPosition, contentLength)) {
if (size >= data.length) {
String[] newdata = new String[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);

View File

@@ -126,21 +126,38 @@ public class JsonByteBufferReader extends JsonReader {
if (ch == '{') return "";
if (ch == 'n' && nextChar() == 'u' && nextChar() == 'l' && nextChar() == 'l') return null;
if (ch == 'N' && nextChar() == 'U' && nextChar() == 'L' && nextChar() == 'L') return null;
throw new ConvertException("a json object text must begin with '{' (position = " + position + ") but '" + ch + "'");
StringBuilder sb = new StringBuilder();
sb.append(ch);
char one;
try {
while ((one = nextChar()) != 0) sb.append(one);
} catch (Exception e) {
}
throw new ConvertException("a json object text must begin with '{' (position = " + position + ") but '" + ch + "' in (" + sb + ")");
}
/**
* 判断下一个非空白字符是否为[
*
* @param member DeMember
* @param decoder Decodeable
*
* @return SIGN_NOLENGTH 或 SIGN_NULL
*/
@Override
public final int readArrayB() {
public final int readArrayB(DeMember member, Decodeable decoder) {
char ch = nextGoodChar();
if (ch == '[' || ch == '{') return SIGN_NOLENGTH;
if (ch == 'n' && nextChar() == 'u' && nextChar() == 'l' && nextChar() == 'l') return SIGN_NULL;
if (ch == 'N' && nextChar() == 'U' && nextChar() == 'L' && nextChar() == 'L') return SIGN_NULL;
throw new ConvertException("a json array text must begin with '[' (position = " + position + ") but '" + ch + "'");
StringBuilder sb = new StringBuilder();
sb.append(ch);
char one;
try {
while ((one = nextChar()) != 0) sb.append(one);
} catch (Exception e) {
}
throw new ConvertException("a json array text must begin with '[' (position = " + position + ") but '" + ch + "' in (" + sb + ")");
}
/**
@@ -150,16 +167,26 @@ public class JsonByteBufferReader extends JsonReader {
public final void readBlank() {
char ch = nextGoodChar();
if (ch == ':') return;
throw new ConvertException("expected a ':' but '" + ch + "'(position = " + position + ")");
StringBuilder sb = new StringBuilder();
sb.append(ch);
char one;
try {
while ((one = nextChar()) != 0) sb.append(one);
} catch (Exception e) {
}
throw new ConvertException("expected a ':' but '" + ch + "'(position = " + position + ") in (" + sb + ")");
}
/**
* 判断对象是否存在下一个属性或者数组是否存在下一个元素
*
* @param startPosition 起始位置
* @param contentLength 内容大小, 不确定的传-1
*
* @return 是否存在
*/
@Override
public final boolean hasNext() {
public boolean hasNext(int startPosition, int contentLength) {
char ch = nextGoodChar();
if (ch == ',') return true;
if (ch == '}' || ch == ']' || ch == 0) return false;
@@ -272,8 +299,10 @@ public class JsonByteBufferReader extends JsonReader {
@Override
public final int readInt() {
char firstchar = nextGoodChar();
boolean quote = false;
if (firstchar == '"' || firstchar == '\'') {
firstchar = nextChar();
quote = true;
firstchar = nextGoodChar();
if (firstchar == '"' || firstchar == '\'') return 0;
}
int value = 0;
@@ -288,6 +317,7 @@ public class JsonByteBufferReader extends JsonReader {
if (ch >= '0' && ch <= '9') {
value = (value << 3) + (value << 1) + (ch - '0');
} else if (ch == '"' || ch == '\'') {
} else if (quote && ch <= ' ') {
} else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') {
backChar(ch);
break;
@@ -306,8 +336,10 @@ public class JsonByteBufferReader extends JsonReader {
@Override
public final long readLong() {
char firstchar = nextGoodChar();
boolean quote = false;
if (firstchar == '"' || firstchar == '\'') {
firstchar = nextChar();
quote = true;
firstchar = nextGoodChar();
if (firstchar == '"' || firstchar == '\'') return 0L;
}
long value = 0;
@@ -322,6 +354,7 @@ public class JsonByteBufferReader extends JsonReader {
if (ch >= '0' && ch <= '9') {
value = (value << 3) + (value << 1) + (ch - '0');
} else if (ch == '"' || ch == '\'') {
} else if (quote && ch <= ' ') {
} else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') {
backChar(ch);
break;

View File

@@ -22,8 +22,6 @@ import org.redkale.util.*;
*/
public class JsonByteBufferWriter extends JsonWriter {
protected static final Charset UTF8 = Charset.forName("UTF-8");
protected Charset charset;
private final Supplier<ByteBuffer> supplier;
@@ -38,7 +36,7 @@ public class JsonByteBufferWriter extends JsonWriter {
protected JsonByteBufferWriter(boolean tiny, Charset charset, Supplier<ByteBuffer> supplier) {
this.tiny = tiny;
this.charset = UTF8.equals(charset) ? null : charset;
this.charset = StandardCharsets.UTF_8.equals(charset) ? null : charset;
this.supplier = supplier;
}
@@ -51,6 +49,7 @@ public class JsonByteBufferWriter extends JsonWriter {
@Override
protected boolean recycle() {
this.index = 0;
this.specify = null;
this.charset = null;
this.buffers = null;
return false;

View File

@@ -80,8 +80,8 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
return writerPool.get().tiny(tiny);
}
public void offerJsonWriter(final JsonWriter out) {
if (out != null) writerPool.accept(out);
public void offerJsonWriter(final JsonWriter writer) {
if (writer != null) writerPool.accept(writer);
}
//------------------------------ convertFrom -----------------------------------------------------------
@@ -139,20 +139,21 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
public String convertTo(final Type type, final Object value) {
if (type == null) return null;
if (value == null) return "null";
final JsonWriter out = writerPool.get().tiny(tiny);
factory.loadEncoder(type).convertTo(out, value);
String result = out.toString();
writerPool.accept(out);
final JsonWriter writer = writerPool.get().tiny(tiny);
writer.specify(type);
factory.loadEncoder(type).convertTo(writer, value);
String result = writer.toString();
writerPool.accept(writer);
return result;
}
@Override
public String convertMapTo(final Object... values) {
if (values == null) return "null";
final JsonWriter out = writerPool.get().tiny(tiny);
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
String result = out.toString();
writerPool.accept(out);
final JsonWriter writer = writerPool.get().tiny(tiny);
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
String result = writer.toString();
writerPool.accept(writer);
return result;
}
@@ -170,6 +171,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
new JsonStreamWriter(tiny, out).writeNull();
} else {
final JsonWriter writer = writerPool.get().tiny(tiny);
writer.specify(type);
factory.loadEncoder(type).convertTo(writer, value);
byte[] bs = writer.toBytes();
writerPool.accept(writer);
@@ -216,6 +218,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
if (value == null) {
out.writeNull();
} else {
out.specify(type);
factory.loadEncoder(type).convertTo(out, value);
}
return out.toBuffers();
@@ -246,6 +249,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
if (value == null) {
writer.writeNull();
} else {
writer.specify(type);
factory.loadEncoder(type).convertTo(writer, value);
}
}
@@ -265,14 +269,15 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
public JsonWriter convertToWriter(final Type type, final Object value) {
if (type == null) return null;
final JsonWriter out = writerPool.get().tiny(tiny);
factory.loadEncoder(type).convertTo(out, value);
return out;
final JsonWriter writer = writerPool.get().tiny(tiny);
writer.specify(type);
factory.loadEncoder(type).convertTo(writer, value);
return writer;
}
public JsonWriter convertMapToWriter(final Object... values) {
final JsonWriter out = writerPool.get().tiny(tiny);
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(out, values);
return out;
final JsonWriter writer = writerPool.get().tiny(tiny);
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
return writer;
}
}

View File

@@ -85,4 +85,9 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
public boolean isReversible() {
return false;
}
@Override
public boolean isFieldSort() {
return true;
}
}

View File

@@ -189,11 +189,14 @@ public class JsonReader extends Reader {
/**
* 判断下一个非空白字符是否为{
*
* @param member DeMember
* @param keydecoder Decodeable
*
* @return SIGN_NOLENGTH 或 SIGN_NULL
*/
@Override
public final int readMapB() {
return readArrayB();
public final int readMapB(DeMember member, Decodeable keydecoder) {
return readArrayB(member, keydecoder);
}
@Override
@@ -203,10 +206,13 @@ public class JsonReader extends Reader {
/**
* 判断下一个非空白字符是否为[
*
* @param member DeMember
* @param decoder Decodeable
*
* @return SIGN_NOLENGTH 或 SIGN_NULL
*/
@Override
public int readArrayB() {
public int readArrayB(DeMember member, Decodeable decoder) {
char ch = this.text[++this.position];
if (ch == '[') return SIGN_NOLENGTH;
if (ch == '{') return SIGN_NOLENGTH;
@@ -244,13 +250,26 @@ public class JsonReader extends Reader {
throw new ConvertException("'" + new String(text) + "'expected a ':' but '" + ch + "'(position = " + position + ") in (" + new String(this.text) + ")");
}
@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 boolean hasNext() {
public boolean hasNext(int startPosition, int contentLength) {
char ch = this.text[++this.position];
if (ch == ',') return true;
if (ch == '}' || ch == ']') return false;
@@ -335,8 +354,16 @@ public class JsonReader extends Reader {
if (firstchar > ' ') break;
}
}
boolean quote = false;
if (firstchar == '"' || firstchar == '\'') {
quote = true;
firstchar = text0[++currpos];
if (firstchar <= ' ') {
for (;;) {
firstchar = text0[++currpos];
if (firstchar > ' ') break;
}
}
if (firstchar == '"' || firstchar == '\'') {
this.position = currpos;
return 0;
@@ -352,7 +379,8 @@ public class JsonReader extends Reader {
if (currpos == eof) break;
char ch = text0[++currpos];
int val = digits[ch];
if (val == -3) break;
if (quote && val == -3) continue;
if (val <= -3) break;
if (val == -1) throw new ConvertException("illegal escape(" + ch + ") (position = " + currpos + ") but '" + ch + "' in (" + new String(this.text) + ")");
if (val != -2) value = value * 10 + val;
}
@@ -377,8 +405,16 @@ public class JsonReader extends Reader {
if (firstchar > ' ') break;
}
}
boolean quote = false;
if (firstchar == '"' || firstchar == '\'') {
quote = true;
firstchar = text0[++currpos];
if (firstchar <= ' ') {
for (;;) {
firstchar = text0[++currpos];
if (firstchar > ' ') break;
}
}
if (firstchar == '"' || firstchar == '\'') {
this.position = currpos;
return 0L;
@@ -394,7 +430,8 @@ public class JsonReader extends Reader {
if (currpos == eof) break;
char ch = text0[++currpos];
int val = digits[ch];
if (val == -3) break;
if (quote && val == -3) continue;
if (val <= -3) break;
if (val == -1) throw new ConvertException("illegal escape(" + ch + ") (position = " + currpos + ") but '" + ch + "' in (" + new String(this.text) + ")");
if (val != -2) value = value * 10 + val;
}
@@ -435,6 +472,41 @@ public class JsonReader extends Reader {
return (byte) readInt();
}
@Override
public final byte[] readByteArray() {
int len = readArrayB(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 final char readChar() {
return (char) readInt();
@@ -448,6 +520,7 @@ public class JsonReader extends Reader {
@Override
public final float readFloat() {
String chars = readSmallString();
if (chars != null) chars = chars.trim();
if (chars == null || chars.isEmpty()) return 0.f;
return Float.parseFloat(chars);
}
@@ -455,6 +528,7 @@ public class JsonReader extends Reader {
@Override
public final double readDouble() {
String chars = readSmallString();
if (chars != null) chars = chars.trim();
if (chars == null || chars.isEmpty()) return 0.0;
return Double.parseDouble(chars);
}
@@ -590,7 +664,8 @@ public class JsonReader extends Reader {
digits[i] = i - 'A' + 10;
}
digits['"'] = digits['\''] = -2; //-2 跳过
digits[','] = digits['}'] = digits[']'] = digits[' '] = digits['\t'] = digits['\r'] = digits['\n'] = digits[':'] = -3; //-3退出
digits[' '] = digits['\t'] = digits['\r'] = digits['\n'] = -3; //-3可能跳过
digits[','] = digits['}'] = digits[']'] = digits[':'] = -4; //-4退出
}
}

View File

@@ -6,7 +6,7 @@
package org.redkale.convert.json;
import java.nio.ByteBuffer;
import org.redkale.convert.Writer;
import org.redkale.convert.*;
import org.redkale.util.*;
/**
@@ -99,6 +99,7 @@ public class JsonWriter extends Writer {
protected boolean recycle() {
this.count = 0;
this.specify = null;
if (this.content.length > defaultSize) {
this.content = new char[defaultSize];
}
@@ -156,9 +157,9 @@ public class JsonWriter extends Writer {
}
@Override
public final void writeFieldName(Attribute attribute) {
public final void writeFieldName(EnMember member) {
if (this.comma) writeTo(',');
writeTo(true, attribute.field());
writeTo(true, member.getAttribute().field());
writeTo(':');
}
@@ -187,6 +188,22 @@ public class JsonWriter extends Writer {
writeInt(value);
}
@Override
public final void writeByteArray(byte[] values) {
if (values == null) {
writeNull();
return;
}
writeArrayB(values.length, null, values);
boolean flag = false;
for (byte v : values) {
if (flag) writeArrayMark();
writeByte(v);
flag = true;
}
writeArrayE();
}
@Override
public final void writeChar(char value) {
writeInt(value);
@@ -312,9 +329,10 @@ public class JsonWriter extends Writer {
}
@Override
public final void writeObjectB(Object obj) {
public final int writeObjectB(Object obj) {
super.writeObjectB(obj);
writeTo('{');
return -1;
}
@Override
@@ -328,8 +346,9 @@ public class JsonWriter extends Writer {
}
@Override
public final void writeArrayB(int size) {
public final int writeArrayB(int size, Encodeable<Writer, Object> encoder, Object obj) {
writeTo('[');
return -1;
}
@Override
@@ -343,8 +362,9 @@ public class JsonWriter extends Writer {
}
@Override
public final void writeMapB(int size) {
public final int writeMapB(int size, Encodeable<Writer, Object> keyEncoder, Encodeable<Writer, Object> valueEncoder, Object obj) {
writeTo('{');
return -1;
}
@Override

View File

@@ -11,7 +11,8 @@ import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.*;
import java.util.function.Consumer;
import javax.net.ssl.SSLContext;
/**
@@ -33,11 +34,16 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
protected volatile long writetime;
//在线数
protected AtomicLong livingCounter;
//关闭数
protected AtomicLong closedCounter;
//在线数
protected AtomicLong livingCounter;
protected Consumer<AsyncConnection> beforeCloseListener;
//关联的事件数, 小于1表示没有事件
protected final AtomicInteger eventing = new AtomicInteger();
public final long getLastReadTime() {
return readtime;
@@ -47,19 +53,49 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
return writetime;
}
public final int increEventing() {
return eventing.incrementAndGet();
}
public final int decreEventing() {
return eventing.decrementAndGet();
}
public abstract boolean isTCP();
public abstract boolean shutdownInput();
public abstract boolean shutdownOutput();
public abstract <T> boolean setOption(SocketOption<T> name, T value);
public abstract Set<SocketOption<?>> supportedOptions();
public abstract SocketAddress getRemoteAddress();
public abstract SocketAddress getLocalAddress();
public abstract int getReadTimeoutSecond();
public abstract int getReadTimeoutSeconds();
public abstract int getWriteTimeoutSecond();
public abstract int getWriteTimeoutSeconds();
public abstract void setReadTimeoutSecond(int readTimeoutSecond);
public abstract void setReadTimeoutSeconds(int readTimeoutSeconds);
public abstract void setWriteTimeoutSecond(int writeTimeoutSecond);
public abstract void setWriteTimeoutSeconds(int writeTimeoutSeconds);
@Override
public abstract Future<Integer> read(ByteBuffer dst);
@Override
public abstract <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler);
public abstract <A> void read(ByteBuffer dst, long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer, ? super A> handler);
@Override
public abstract Future<Integer> write(ByteBuffer src);
@Override
public abstract <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler);
public final <A> void write(ByteBuffer[] srcs, A attachment, CompletionHandler<Integer, ? super A> handler) {
write(srcs, 0, srcs.length, attachment, handler);
@@ -74,6 +110,11 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
}
}
public AsyncConnection beforeCloseListener(Consumer<AsyncConnection> beforeCloseListener) {
this.beforeCloseListener = beforeCloseListener;
return this;
}
@Override
public void close() throws IOException {
if (closedCounter != null) {
@@ -84,6 +125,11 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
livingCounter.decrementAndGet();
livingCounter = null;
}
if (beforeCloseListener != null)
try {
beforeCloseListener.accept(this);
} catch (Exception io) {
}
if (attributes == null) return;
try {
for (Object obj : attributes.values()) {
@@ -128,61 +174,44 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
/**
* 创建TCP协议客户端连接
*
* @param address 连接点子
* @param group 连接AsynchronousChannelGroup
* @param readTimeoutSecond 读取超时秒数
* @param writeTimeoutSecond 写入超时秒数
* @param address 连接点子
* @param group 连接AsynchronousChannelGroup
* @param readTimeoutSeconds 读取超时秒数
* @param writeTimeoutSeconds 写入超时秒数
*
* @return 连接CompletableFuture
*/
public static CompletableFuture<AsyncConnection> createTCP(final AsynchronousChannelGroup group, final SocketAddress address,
final int readTimeoutSecond, final int writeTimeoutSecond) {
return createTCP(group, null, address, false, readTimeoutSecond, writeTimeoutSecond);
final int readTimeoutSeconds, final int writeTimeoutSeconds) {
return createTCP(group, null, address, readTimeoutSeconds, writeTimeoutSeconds);
}
/**
* 创建TCP协议客户端连接
*
* @param address 连接点子
* @param sslContext SSLContext
* @param group 连接AsynchronousChannelGroup
* @param readTimeoutSecond 读取超时秒数
* @param writeTimeoutSecond 写入超时秒数
* @param address 连接点子
* @param sslContext SSLContext
* @param group 连接AsynchronousChannelGroup
* @param readTimeoutSeconds 读取超时秒数
* @param writeTimeoutSeconds 写入超时秒数
*
* @return 连接CompletableFuture
*/
public static CompletableFuture<AsyncConnection> createTCP(final AsynchronousChannelGroup group, final SSLContext sslContext,
final SocketAddress address, final int readTimeoutSecond, final int writeTimeoutSecond) {
return createTCP(group, sslContext, address, false, readTimeoutSecond, writeTimeoutSecond);
}
/**
* 创建TCP协议客户端连接
*
* @param address 连接点子
* @param sslContext SSLContext
* @param group 连接AsynchronousChannelGroup
* @param noDelay TcpNoDelay
* @param readTimeoutSecond 读取超时秒数
* @param writeTimeoutSecond 写入超时秒数
*
* @return 连接CompletableFuture
*/
public static CompletableFuture<AsyncConnection> createTCP(final AsynchronousChannelGroup group, final SSLContext sslContext,
final SocketAddress address, final boolean noDelay, final int readTimeoutSecond, final int writeTimeoutSecond) {
final CompletableFuture future = new CompletableFuture();
final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
final CompletableFuture<AsyncConnection> future = new CompletableFuture<>();
try {
final AsynchronousSocketChannel channel = AsynchronousSocketChannel.open(group);
try {
channel.setOption(StandardSocketOptions.TCP_NODELAY, true);
channel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
} catch (IOException e) {
}
channel.connect(address, null, new CompletionHandler<Void, Void>() {
@Override
public void completed(Void result, Void attachment) {
if (noDelay) {
try {
channel.setOption(StandardSocketOptions.TCP_NODELAY, true);
} catch (IOException e) {
}
}
future.complete(create(channel, sslContext, address, readTimeoutSecond, writeTimeoutSecond));
future.complete(create(channel, sslContext, address, readTimeoutSeconds, writeTimeoutSeconds));
}
@Override
@@ -196,287 +225,6 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
return future;
}
private static class BIOUDPAsyncConnection extends AsyncConnection {
private int readTimeoutSecond;
private int writeTimeoutSecond;
private final DatagramChannel channel;
private final SocketAddress remoteAddress;
private final boolean client;
public BIOUDPAsyncConnection(final DatagramChannel ch, SocketAddress addr,
final boolean client0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
this.channel = ch;
this.client = client0;
this.readTimeoutSecond = readTimeoutSecond0;
this.writeTimeoutSecond = writeTimeoutSecond0;
this.remoteAddress = addr;
}
@Override
public void setReadTimeoutSecond(int readTimeoutSecond) {
this.readTimeoutSecond = readTimeoutSecond;
}
@Override
public void setWriteTimeoutSecond(int writeTimeoutSecond) {
this.writeTimeoutSecond = writeTimeoutSecond;
}
@Override
public int getReadTimeoutSecond() {
return this.readTimeoutSecond;
}
@Override
public int getWriteTimeoutSecond() {
return this.writeTimeoutSecond;
}
@Override
public final SocketAddress getRemoteAddress() {
return remoteAddress;
}
@Override
public SocketAddress getLocalAddress() {
try {
return channel.getLocalAddress();
} catch (IOException e) {
return null;
}
}
@Override
public <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) {
try {
int rs = 0;
for (int i = offset; i < offset + length; i++) {
rs += channel.send(srcs[i], remoteAddress);
if (i != offset) Thread.sleep(10);
}
this.writetime = System.currentTimeMillis();
if (handler != null) handler.completed(rs, attachment);
} catch (Exception e) {
if (handler != null) handler.failed(e, attachment);
}
}
@Override
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
try {
int rs = channel.read(dst);
this.readtime = System.currentTimeMillis();
if (handler != null) handler.completed(rs, attachment);
} catch (IOException e) {
if (handler != null) handler.failed(e, attachment);
}
}
@Override
public Future<Integer> read(ByteBuffer dst) {
try {
int rs = channel.read(dst);
this.readtime = System.currentTimeMillis();
return CompletableFuture.completedFuture(rs);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
try {
int rs = channel.send(src, remoteAddress);
this.writetime = System.currentTimeMillis();
if (handler != null) handler.completed(rs, attachment);
} catch (IOException e) {
if (handler != null) handler.failed(e, attachment);
}
}
@Override
public Future<Integer> write(ByteBuffer src) {
try {
int rs = channel.send(src, remoteAddress);
this.writetime = System.currentTimeMillis();
return CompletableFuture.completedFuture(rs);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public final void close() throws IOException {
super.close();
if (client) channel.close();
}
@Override
public final boolean isOpen() {
return channel.isOpen();
}
@Override
public final boolean isTCP() {
return false;
}
}
public static AsyncConnection create(final DatagramChannel ch, SocketAddress addr,
final boolean client0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
return new BIOUDPAsyncConnection(ch, addr, client0, readTimeoutSecond0, writeTimeoutSecond0);
}
private static class BIOTCPAsyncConnection extends AsyncConnection {
private int readTimeoutSecond;
private int writeTimeoutSecond;
private final Socket socket;
private final ReadableByteChannel readChannel;
private final WritableByteChannel writeChannel;
private final SocketAddress remoteAddress;
public BIOTCPAsyncConnection(final Socket socket, final SocketAddress addr0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
this.socket = socket;
ReadableByteChannel rc = null;
WritableByteChannel wc = null;
try {
socket.setSoTimeout(Math.max(readTimeoutSecond0, writeTimeoutSecond0));
rc = Channels.newChannel(socket.getInputStream());
wc = Channels.newChannel(socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
this.readChannel = rc;
this.writeChannel = wc;
this.readTimeoutSecond = readTimeoutSecond0;
this.writeTimeoutSecond = writeTimeoutSecond0;
SocketAddress addr = addr0;
if (addr == null) {
try {
addr = socket.getRemoteSocketAddress();
} catch (Exception e) {
//do nothing
}
}
this.remoteAddress = addr;
}
@Override
public boolean isTCP() {
return true;
}
@Override
public SocketAddress getRemoteAddress() {
return remoteAddress;
}
@Override
public SocketAddress getLocalAddress() {
return socket.getLocalSocketAddress();
}
@Override
public int getReadTimeoutSecond() {
return readTimeoutSecond;
}
@Override
public int getWriteTimeoutSecond() {
return writeTimeoutSecond;
}
@Override
public void setReadTimeoutSecond(int readTimeoutSecond) {
this.readTimeoutSecond = readTimeoutSecond;
}
@Override
public void setWriteTimeoutSecond(int writeTimeoutSecond) {
this.writeTimeoutSecond = writeTimeoutSecond;
}
@Override
public <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) {
try {
int rs = 0;
for (int i = offset; i < offset + length; i++) {
rs += writeChannel.write(srcs[i]);
}
this.writetime = System.currentTimeMillis();
if (handler != null) handler.completed(rs, attachment);
} catch (IOException e) {
if (handler != null) handler.failed(e, attachment);
}
}
@Override
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
try {
int rs = readChannel.read(dst);
this.readtime = System.currentTimeMillis();
if (handler != null) handler.completed(rs, attachment);
} catch (IOException e) {
if (handler != null) handler.failed(e, attachment);
}
}
@Override
public Future<Integer> read(ByteBuffer dst) {
try {
int rs = readChannel.read(dst);
this.readtime = System.currentTimeMillis();
return CompletableFuture.completedFuture(rs);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
try {
int rs = writeChannel.write(src);
this.writetime = System.currentTimeMillis();
if (handler != null) handler.completed(rs, attachment);
} catch (IOException e) {
if (handler != null) handler.failed(e, attachment);
}
}
@Override
public Future<Integer> write(ByteBuffer src) {
try {
int rs = writeChannel.write(src);
this.writetime = System.currentTimeMillis();
return CompletableFuture.completedFuture(rs);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void close() throws IOException {
super.close();
this.socket.close();
}
@Override
public boolean isOpen() {
return !socket.isClosed();
}
}
/**
* 通常用于 ssl socket
*
@@ -489,150 +237,68 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
}
public static AsyncConnection create(final Socket socket, final SocketAddress addr0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
return new BIOTCPAsyncConnection(socket, addr0, readTimeoutSecond0, writeTimeoutSecond0);
return new TcpBioAsyncConnection(socket, addr0, readTimeoutSecond0, writeTimeoutSecond0, null, null);
}
private static class AIOTCPAsyncConnection extends AsyncConnection {
public static AsyncConnection create(final Socket socket, final SocketAddress addr0, final int readTimeoutSecond0,
final int writeTimeoutSecond0, final AtomicLong livingCounter, final AtomicLong closedCounter) {
return new TcpBioAsyncConnection(socket, addr0, readTimeoutSecond0, writeTimeoutSecond0, livingCounter, closedCounter);
}
private int readTimeoutSecond;
public static AsyncConnection create(final SocketChannel ch, SocketAddress addr, final Selector selector,
final int readTimeoutSeconds0, final int writeTimeoutSeconds0) {
return new TcpNioAsyncConnection(ch, addr, selector, readTimeoutSeconds0, writeTimeoutSeconds0, null, null);
}
private int writeTimeoutSecond;
public static AsyncConnection create(final SocketChannel ch, final SocketAddress addr0, final Selector selector, final Context context) {
return new TcpNioAsyncConnection(ch, addr0, selector, context.readTimeoutSeconds, context.writeTimeoutSeconds, null, null);
}
private final AsynchronousSocketChannel channel;
public static AsyncConnection create(final SocketChannel ch, SocketAddress addr, final Selector selector,
final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
final AtomicLong livingCounter, final AtomicLong closedCounter) {
return new TcpNioAsyncConnection(ch, addr, selector, readTimeoutSeconds0, writeTimeoutSeconds0, livingCounter, closedCounter);
}
private final SocketAddress remoteAddress;
public AIOTCPAsyncConnection(final AsynchronousSocketChannel ch, SSLContext sslContext,
final SocketAddress addr0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
this.channel = ch;
this.sslContext = sslContext;
this.readTimeoutSecond = readTimeoutSecond0;
this.writeTimeoutSecond = writeTimeoutSecond0;
SocketAddress addr = addr0;
if (addr == null) {
try {
addr = ch.getRemoteAddress();
} catch (Exception e) {
//do nothing
}
}
this.remoteAddress = addr;
}
@Override
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
this.readtime = System.currentTimeMillis();
if (readTimeoutSecond > 0) {
channel.read(dst, readTimeoutSecond, TimeUnit.SECONDS, attachment, handler);
} else {
channel.read(dst, attachment, handler);
}
}
@Override
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
this.writetime = System.currentTimeMillis();
if (writeTimeoutSecond > 0) {
channel.write(src, writeTimeoutSecond, TimeUnit.SECONDS, attachment, handler);
} else {
channel.write(src, attachment, handler);
}
}
@Override
public <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, final CompletionHandler<Integer, ? super A> handler) {
this.writetime = System.currentTimeMillis();
channel.write(srcs, offset, length, writeTimeoutSecond > 0 ? writeTimeoutSecond : 60, TimeUnit.SECONDS,
attachment, new CompletionHandler<Long, A>() {
@Override
public void completed(Long result, A attachment) {
handler.completed(result.intValue(), attachment);
}
@Override
public void failed(Throwable exc, A attachment) {
handler.failed(exc, attachment);
}
});
}
@Override
public void setReadTimeoutSecond(int readTimeoutSecond) {
this.readTimeoutSecond = readTimeoutSecond;
}
@Override
public void setWriteTimeoutSecond(int writeTimeoutSecond) {
this.writeTimeoutSecond = writeTimeoutSecond;
}
@Override
public int getReadTimeoutSecond() {
return this.readTimeoutSecond;
}
@Override
public int getWriteTimeoutSecond() {
return this.writeTimeoutSecond;
}
@Override
public final SocketAddress getRemoteAddress() {
return remoteAddress;
}
@Override
public SocketAddress getLocalAddress() {
try {
return channel.getLocalAddress();
} catch (IOException e) {
return null;
}
}
@Override
public final Future<Integer> read(ByteBuffer dst) {
return channel.read(dst);
}
@Override
public final Future<Integer> write(ByteBuffer src) {
return channel.write(src);
}
@Override
public final void close() throws IOException {
super.close();
channel.close();
}
@Override
public final boolean isOpen() {
return channel.isOpen();
}
@Override
public final boolean isTCP() {
return true;
}
public static AsyncConnection create(final DatagramChannel ch, SocketAddress addr,
final boolean client0, final int readTimeoutSeconds0, final int writeTimeoutSeconds0) {
return new UdpBioAsyncConnection(ch, addr, client0, readTimeoutSeconds0, writeTimeoutSeconds0, null, null);
}
public static AsyncConnection create(final DatagramChannel ch, SocketAddress addr,
final boolean client0, final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
final AtomicLong livingCounter, final AtomicLong closedCounter) {
return new UdpBioAsyncConnection(ch, addr, client0, readTimeoutSeconds0, writeTimeoutSeconds0, livingCounter, closedCounter);
}
public static AsyncConnection create(final AsynchronousSocketChannel ch) {
return create(ch, null, 0, 0);
}
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0, final int readTimeoutSecond, final int writeTimeoutSecond) {
return new AIOTCPAsyncConnection(ch, null, addr0, readTimeoutSecond, writeTimeoutSecond);
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
return new TcpAioAsyncConnection(ch, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
}
public static AsyncConnection create(final AsynchronousSocketChannel ch, SSLContext sslContext, final SocketAddress addr0, final int readTimeoutSecond, final int writeTimeoutSecond) {
return new AIOTCPAsyncConnection(ch, sslContext, addr0, readTimeoutSecond, writeTimeoutSecond);
public static AsyncConnection create(final AsynchronousSocketChannel ch, SSLContext sslContext, final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
return new TcpAioAsyncConnection(ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
}
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0, final Context context) {
return new AIOTCPAsyncConnection(ch, context.sslContext, addr0, context.readTimeoutSecond, context.writeTimeoutSecond);
return new TcpAioAsyncConnection(ch, context.sslContext, addr0, context.readTimeoutSeconds, context.writeTimeoutSeconds, null, null);
}
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0, final int readTimeoutSeconds,
final int writeTimeoutSeconds, final AtomicLong livingCounter, final AtomicLong closedCounter) {
return new TcpAioAsyncConnection(ch, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
}
public static AsyncConnection create(final AsynchronousSocketChannel ch, SSLContext sslContext, final SocketAddress addr0, final int readTimeoutSeconds,
final int writeTimeoutSeconds, final AtomicLong livingCounter, final AtomicLong closedCounter) {
return new TcpAioAsyncConnection(ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
}
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0,
final Context context, final AtomicLong livingCounter, final AtomicLong closedCounter) {
return new TcpAioAsyncConnection(ch, context.sslContext, addr0, context.readTimeoutSeconds, context.writeTimeoutSeconds, livingCounter, closedCounter);
}
}

View File

@@ -5,10 +5,8 @@
*/
package org.redkale.net;
import java.io.IOException;
import java.net.*;
import java.nio.*;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.charset.*;
import java.util.concurrent.*;
import java.util.function.*;
@@ -28,8 +26,6 @@ import org.redkale.util.*;
*/
public class Context {
private static final Charset UTF8 = Charset.forName("UTF-8");
//服务启动时间
protected final long serverStartTime;
@@ -57,14 +53,20 @@ public class Context {
//字符集
protected final Charset charset;
//最大连接数, 为0表示没限制
protected final int maxconns;
//请求内容的大小上限, 默认64K
protected final int maxbody;
//keep alive IO读取的超时时间
protected final int aliveTimeoutSeconds;
//IO读取的超时时间
protected final int readTimeoutSecond;
protected final int readTimeoutSeconds;
//IO写入的超时时间
protected final int writeTimeoutSecond;
protected final int writeTimeoutSeconds;
//日志Logger
protected final Logger logger;
@@ -78,10 +80,17 @@ public class Context {
//依赖注入工厂类
protected final ResourceFactory resourceFactory;
public Context(ContextConfig config) {
this(config.serverStartTime, config.logger, config.executor, config.sslContext,
config.bufferCapacity, config.bufferPool, config.responsePool, config.maxconns, config.maxbody,
config.charset, config.address, config.resourceFactory, config.prepare,
config.aliveTimeoutSeconds, config.readTimeoutSeconds, config.writeTimeoutSeconds);
}
public Context(long serverStartTime, Logger logger, ThreadPoolExecutor executor, SSLContext sslContext,
int bufferCapacity, ObjectPool<ByteBuffer> bufferPool, ObjectPool<Response> responsePool,
int bufferCapacity, ObjectPool<ByteBuffer> bufferPool, ObjectPool<Response> responsePool, final int maxconns,
final int maxbody, Charset charset, InetSocketAddress address, ResourceFactory resourceFactory,
final PrepareServlet prepare, final int readTimeoutSecond, final int writeTimeoutSecond) {
final PrepareServlet prepare, final int aliveTimeoutSeconds, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
this.serverStartTime = serverStartTime;
this.logger = logger;
this.executor = executor;
@@ -89,13 +98,15 @@ public class Context {
this.bufferCapacity = bufferCapacity;
this.bufferPool = bufferPool;
this.responsePool = responsePool;
this.maxconns = maxconns;
this.maxbody = maxbody;
this.charset = UTF8.equals(charset) ? null : charset;
this.charset = StandardCharsets.UTF_8.equals(charset) ? null : charset;
this.address = address;
this.prepare = prepare;
this.resourceFactory = resourceFactory;
this.readTimeoutSecond = readTimeoutSecond;
this.writeTimeoutSecond = writeTimeoutSecond;
this.aliveTimeoutSeconds = aliveTimeoutSeconds;
this.readTimeoutSeconds = readTimeoutSeconds;
this.writeTimeoutSeconds = writeTimeoutSeconds;
this.jsonFactory = JsonFactory.root();
this.bsonFactory = BsonFactory.root();
}
@@ -108,6 +119,10 @@ public class Context {
return sslContext;
}
public int getMaxconns() {
return maxconns;
}
public int getMaxbody() {
return maxbody;
}
@@ -128,10 +143,6 @@ public class Context {
return executor.submit(r);
}
public AsynchronousChannelGroup createAsynchronousChannelGroup() throws IOException {
return AsynchronousChannelGroup.withThreadPool(executor);
}
public void runAsync(Runnable r) {
executor.execute(r);
}
@@ -144,15 +155,19 @@ public class Context {
return bufferPool;
}
protected Consumer<ByteBuffer> getBufferConsumer() {
return bufferPool;
}
public ByteBuffer pollBuffer() {
return bufferPool.get();
}
public void offerBuffer(ByteBuffer buffer) {
protected void offerBuffer(ByteBuffer buffer) {
bufferPool.accept(buffer);
}
public void offerBuffer(ByteBuffer... buffers) {
protected void offerBuffer(ByteBuffer... buffers) {
if (buffers == null) return;
for (ByteBuffer buffer : buffers) {
bufferPool.accept(buffer);
@@ -163,12 +178,16 @@ public class Context {
return logger;
}
public int getReadTimeoutSecond() {
return readTimeoutSecond;
public int getAliveTimeoutSeconds() {
return aliveTimeoutSeconds;
}
public int getWriteTimeoutSecond() {
return writeTimeoutSecond;
public int getReadTimeoutSeconds() {
return readTimeoutSeconds;
}
public int getWriteTimeoutSeconds() {
return writeTimeoutSeconds;
}
public JsonConvert getJsonConvert() {
@@ -178,4 +197,60 @@ public class Context {
public BsonConvert getBsonConvert() {
return bsonFactory.getConvert();
}
public static class ContextConfig {
//服务启动时间
public long serverStartTime;
//Server的线程池
public ThreadPoolExecutor executor;
//SSL
public SSLContext sslContext;
//ByteBuffer的容量默认8K
public int bufferCapacity;
//ByteBuffer对象池
public ObjectPool<ByteBuffer> bufferPool;
//Response对象池
public ObjectPool<Response> responsePool;
//服务的根Servlet
public PrepareServlet prepare;
//服务的监听地址
public InetSocketAddress address;
//字符集
public Charset charset;
//请求内容的大小上限, 默认64K
public int maxbody;
//最大连接数, 为0表示没限制
public int maxconns;
//keep alive IO读取的超时时间
public int aliveTimeoutSeconds;
//IO读取的超时时间
public int readTimeoutSeconds;
//IO写入的超时时间
public int writeTimeoutSeconds;
//日志Logger
public Logger logger;
//依赖注入工厂类
public ResourceFactory resourceFactory;
@Override
public String toString() {
return JsonConvert.root().convertTo(this);
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* 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.net;
import java.nio.ByteBuffer;
import java.util.function.*;
/**
* 加密解密接口
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public interface Cryptor {
/**
* 加密
*
* @param buffers 待加密数据
* @param supplier ByteBuffer生成器
* @param consumer ByteBuffer回收器
*
* @return 加密后数据
*/
public ByteBuffer[] encrypt(ByteBuffer[] buffers, final Supplier<ByteBuffer> supplier, final Consumer<ByteBuffer> consumer);
/**
* 解密
*
* @param buffers 待解密数据
* @param supplier ByteBuffer生成器
* @param consumer ByteBuffer回收器
*
* @return 解密后数据
*/
public ByteBuffer[] decrypt(ByteBuffer[] buffers, final Supplier<ByteBuffer> supplier, final Consumer<ByteBuffer> consumer);
}

View File

@@ -5,8 +5,10 @@
*/
package org.redkale.net;
import java.io.IOException;
import java.nio.*;
import java.nio.channels.*;
import java.util.concurrent.TimeUnit;
import java.util.logging.*;
import org.redkale.util.*;
@@ -19,7 +21,7 @@ import org.redkale.util.*;
* @author zhangjx
*/
@SuppressWarnings("unchecked")
public final class PrepareRunner implements Runnable {
public class PrepareRunner implements Runnable {
private final AsyncConnection channel;
@@ -27,20 +29,24 @@ public final class PrepareRunner implements Runnable {
private ByteBuffer data;
public PrepareRunner(Context context, AsyncConnection channel, ByteBuffer data) {
private Response response;
public PrepareRunner(Context context, AsyncConnection channel, ByteBuffer data, Response response) {
this.context = context;
this.channel = channel;
this.data = data;
this.response = response;
}
@Override
public void run() {
final boolean keepalive = response != null;
final PrepareServlet prepare = context.prepare;
final ObjectPool<? extends Response> responsePool = context.responsePool;
if (data != null) { //BIO模式的UDP连接创建AsyncConnection时已经获取到ByteBuffer数据了
final Response response = responsePool.get();
response.init(channel);
if (response == null) response = responsePool.get();
try {
response.init(channel);
prepare.prepare(data, response.request, response);
} catch (Throwable t) {
context.logger.log(Level.WARNING, "prepare servlet abort, forece to close channel ", t);
@@ -48,20 +54,18 @@ public final class PrepareRunner implements Runnable {
}
return;
}
final Response response = responsePool.get();
if (response == null) response = responsePool.get();
final ByteBuffer buffer = response.request.pollReadBuffer();
try {
channel.read(buffer, null, new CompletionHandler<Integer, Void>() {
channel.read(buffer, keepalive ? context.getAliveTimeoutSeconds() : 0, TimeUnit.SECONDS, null,
new CompletionHandler<Integer, Void>() {
@Override
public void completed(Integer count, Void attachment1) {
if (count < 1 && buffer.remaining() == buffer.limit()) {
try {
response.request.offerReadBuffer(buffer);
response.finish(true);
channel.close();
} catch (Exception e) {
context.logger.log(Level.FINEST, "PrepareRunner close channel erroneous on no read bytes", e);
}
if (count < 1) {
response.request.offerReadBuffer(buffer);
channel.dispose();// response.init(channel); 在调用之前异常
response.removeChannel();
response.finish(true);
return;
}
// { //测试
@@ -83,23 +87,58 @@ public final class PrepareRunner implements Runnable {
@Override
public void failed(Throwable exc, Void attachment2) {
response.request.offerReadBuffer(buffer);
channel.dispose();// response.init(channel); 在调用之前异常
response.removeChannel();
response.finish(true);
try {
channel.close();
} catch (Exception e) {
if (exc != null && context.logger.isLoggable(Level.FINEST)) {
context.logger.log(Level.FINEST, "Servlet Handler read channel erroneous, forece to close channel ", exc);
}
if (exc != null) context.logger.log(Level.FINEST, "Servlet Handler read channel erroneous, forece to close channel ", exc);
}
});
} catch (Exception te) {
response.request.offerReadBuffer(buffer);
channel.dispose();// response.init(channel); 在调用之前异常
response.removeChannel();
response.finish(true);
try {
channel.close();
} catch (Exception e) {
if (te != null && context.logger.isLoggable(Level.FINEST)) {
context.logger.log(Level.FINEST, "Servlet read channel erroneous, forece to close channel ", te);
}
if (te != null) context.logger.log(Level.FINEST, "Servlet read channel erroneous, forece to close channel ", te);
}
}
protected void prepare(ByteBuffer buffer, Request request, Response response) throws IOException {
context.prepare.prepare(buffer, request, response);
}
protected void initResponse(Response response, AsyncConnection channel) {
response.init(channel);
}
protected Response pollResponse() {
return context.responsePool.get();
}
protected Request pollRequest(Response response) {
return response.request;
}
protected AsyncConnection removeChannel(Response response) {
return response.removeChannel();
}
protected ByteBuffer pollReadBuffer(Request request) {
return request.pollReadBuffer();
}
protected ByteBuffer pollReadBuffer(Response response) {
return response.request.pollReadBuffer();
}
protected void offerReadBuffer(Request request, ByteBuffer buffer) {
request.offerReadBuffer(buffer);
}
protected void offerReadBuffer(Response response, ByteBuffer buffer) {
response.request.offerReadBuffer(buffer);
}
}

View File

@@ -210,7 +210,7 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
@SuppressWarnings("unchecked")
public abstract void addServlet(S servlet, Object attachment, AnyValue conf, K... mappings);
public final void prepare(final ByteBuffer buffer, final R request, final P response) throws IOException {
public void prepare(final ByteBuffer buffer, final R request, final P response) throws IOException {
executeCounter.incrementAndGet();
final int rs = request.readHeader(buffer);
if (rs < 0) {
@@ -218,7 +218,11 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
if (rs != Integer.MIN_VALUE) illRequestCounter.incrementAndGet();
response.finish(true);
} else if (rs == 0) {
request.offerReadBuffer(buffer);
if (buffer.hasRemaining()) {
request.setMoredata(buffer);
} else {
request.offerReadBuffer(buffer);
}
request.prepare();
response.filter = this.headFilter;
response.servlet = this;
@@ -236,7 +240,11 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
buffer.clear();
request.channel.read(buffer, buffer, this);
} else {
request.offerReadBuffer(buffer);
if (buffer.hasRemaining()) {
request.setMoredata(buffer);
} else {
request.offerReadBuffer(buffer);
}
request.prepare();
try {
response.filter = PrepareServlet.this.headFilter;

View File

@@ -7,11 +7,9 @@ package org.redkale.net;
import java.io.IOException;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import org.redkale.util.AnyValue;
/**
* 协议底层Server
@@ -32,10 +30,12 @@ public abstract class ProtocolServer {
//在线数
protected final AtomicLong livingCounter = new AtomicLong();
protected final Context context;
//最大连接数小于1表示无限制
protected int maxconns;
public abstract void open() throws IOException;
public abstract void open(AnyValue config) throws IOException;
public abstract void bind(SocketAddress local, int backlog) throws IOException;
@@ -43,15 +43,14 @@ public abstract class ProtocolServer {
public abstract <T> void setOption(SocketOption<T> name, T value) throws IOException;
public abstract void accept();
public void setMaxconns(int maxconns) {
this.maxconns = maxconns;
}
public abstract void accept() throws IOException;
public abstract void close() throws IOException;
public abstract AsynchronousChannelGroup getChannelGroup();
protected ProtocolServer(Context context) {
this.context = context;
this.maxconns = context.getMaxconns();
}
public long getCreateCount() {
return createCounter.longValue();
@@ -66,176 +65,31 @@ public abstract class ProtocolServer {
}
//---------------------------------------------------------------------
public static ProtocolServer create(String protocol, Context context) {
if ("TCP".equalsIgnoreCase(protocol)) return new ProtocolTCPServer(context);
if ("UDP".equalsIgnoreCase(protocol)) return new ProtocolUDPServer(context);
throw new RuntimeException("ProtocolServer not support protocol " + protocol);
}
private static final class ProtocolUDPServer extends ProtocolServer {
private boolean running;
private final Context context;
private DatagramChannel serverChannel;
public ProtocolUDPServer(Context context) {
this.context = context;
}
@Override
public void open() throws IOException {
DatagramChannel ch = DatagramChannel.open();
ch.configureBlocking(true);
this.serverChannel = ch;
}
@Override
public void bind(SocketAddress local, int backlog) throws IOException {
this.serverChannel.bind(local);
}
@Override
public <T> void setOption(SocketOption<T> name, T value) throws IOException {
this.serverChannel.setOption(name, value);
}
@Override
public <T> Set<SocketOption<?>> supportedOptions() {
return this.serverChannel.supportedOptions();
}
@Override
public void accept() {
final DatagramChannel serchannel = this.serverChannel;
final int readTimeoutSecond = this.context.readTimeoutSecond;
final int writeTimeoutSecond = this.context.writeTimeoutSecond;
final CountDownLatch cdl = new CountDownLatch(1);
this.running = true;
new Thread() {
@Override
public void run() {
cdl.countDown();
while (running) {
final ByteBuffer buffer = context.pollBuffer();
try {
SocketAddress address = serchannel.receive(buffer);
buffer.flip();
AsyncConnection conn = AsyncConnection.create(serchannel, address, false, readTimeoutSecond, writeTimeoutSecond);
context.runAsync(new PrepareRunner(context, conn, buffer));
} catch (Exception e) {
context.offerBuffer(buffer);
}
}
}
}.start();
try {
cdl.await();
} catch (Exception e) {
e.printStackTrace();
public static ProtocolServer create(String protocol, Context context, ClassLoader classLoader, String netimpl) {
if (netimpl != null) netimpl = netimpl.trim();
if ("TCP".equalsIgnoreCase(protocol)) {
if (netimpl == null || netimpl.isEmpty()) {
return new TcpAioProtocolServer(context);
} else if ("aio".equalsIgnoreCase(netimpl)) {
return new TcpAioProtocolServer(context);
} else if ("nio".equalsIgnoreCase(netimpl)) {
return new TcpNioProtocolServer(context);
}
} else if ("UDP".equalsIgnoreCase(protocol)) {
if (netimpl == null || netimpl.isEmpty()) {
return new UdpBioProtocolServer(context);
} else if ("bio".equalsIgnoreCase(netimpl)) {
return new UdpBioProtocolServer(context);
}
} else if (netimpl == null || netimpl.isEmpty()) {
throw new RuntimeException("ProtocolServer not support protocol " + protocol);
}
@Override
public void close() throws IOException {
this.running = false;
this.serverChannel.close();
}
@Override
public AsynchronousChannelGroup getChannelGroup() {
return null;
}
@Override
public long getCreateCount() {
return -1;
}
@Override
public long getClosedCount() {
return -1;
}
@Override
public long getLivingCount() {
return -1;
}
}
private static final class ProtocolTCPServer extends ProtocolServer {
private final Context context;
private AsynchronousChannelGroup group;
private AsynchronousServerSocketChannel serverChannel;
public ProtocolTCPServer(Context context) {
this.context = context;
}
@Override
public void open() throws IOException {
group = AsynchronousChannelGroup.withCachedThreadPool(context.executor, 1);
this.serverChannel = AsynchronousServerSocketChannel.open(group);
}
@Override
public void bind(SocketAddress local, int backlog) throws IOException {
this.serverChannel.bind(local, backlog);
}
@Override
public <T> void setOption(SocketOption<T> name, T value) throws IOException {
this.serverChannel.setOption(name, value);
}
@Override
public <T> Set<SocketOption<?>> supportedOptions() {
return this.serverChannel.supportedOptions();
}
@Override
public void accept() {
final AsynchronousServerSocketChannel serchannel = this.serverChannel;
serchannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
@Override
public void completed(final AsynchronousSocketChannel channel, Void attachment) {
serchannel.accept(null, this);
if (maxconns > 0 && livingCounter.get() >= maxconns) {
try {
channel.close();
} catch (Exception e) {
}
return;
}
createCounter.incrementAndGet();
livingCounter.incrementAndGet();
AsyncConnection conn = AsyncConnection.create(channel, null, context);
conn.livingCounter = livingCounter;
conn.closedCounter = closedCounter;
context.runAsync(new PrepareRunner(context, conn, null));
}
@Override
public void failed(Throwable exc, Void attachment) {
serchannel.accept(null, this);
//if (exc != null) context.logger.log(Level.FINEST, AsynchronousServerSocketChannel.class.getSimpleName() + " accept erroneous", exc);
}
});
}
@Override
public void close() throws IOException {
this.serverChannel.close();
}
@Override
public AsynchronousChannelGroup getChannelGroup() {
return this.group;
try {
if (classLoader == null) classLoader = Thread.currentThread().getContextClassLoader();
Class clazz = classLoader.loadClass(netimpl);
return (ProtocolServer) clazz.getDeclaredConstructor(Context.class).newInstance(context);
} catch (Exception e) {
throw new RuntimeException("ProtocolServer(netimple=" + netimpl + ") newinstance error", e);
}
}

View File

@@ -31,6 +31,10 @@ public abstract class Request<C extends Context> {
protected boolean keepAlive;
protected boolean more; //pipeline模式
protected ByteBuffer moredata; //pipeline模式
protected AsyncConnection channel;
protected ByteBuffer readBuffer;
@@ -50,6 +54,16 @@ public abstract class Request<C extends Context> {
this.jsonConvert = context.getJsonConvert();
}
protected void setMoredata(ByteBuffer buffer) {
this.moredata = buffer;
}
protected ByteBuffer removeMoredata() {
ByteBuffer rs = this.moredata;
this.moredata = null;
return rs;
}
protected ByteBuffer pollReadBuffer() {
ByteBuffer buffer = this.readBuffer;
this.readBuffer = null;
@@ -90,8 +104,10 @@ public abstract class Request<C extends Context> {
protected void recycle() {
createtime = 0;
keepAlive = false;
more = false;
moredata = null;
attributes.clear();
channel = null; // close it by response
channel = null; // close it by response
}
protected <T> T setProperty(String name, T value) {

View File

@@ -156,6 +156,10 @@ public abstract class Response<C extends Context, R extends Request<C>> {
return bodyBufferSupplier;
}
protected void offerBuffer(ByteBuffer... buffers) {
context.offerBuffer(buffers);
}
protected AsyncConnection removeChannel() {
AsyncConnection ch = this.channel;
this.channel = null;
@@ -169,28 +173,12 @@ public abstract class Response<C extends Context, R extends Request<C>> {
protected boolean recycle() {
if (!inited) return false;
boolean keepAlive = request.keepAlive;
if (recycleListener != null) {
try {
recycleListener.accept(request, this);
} catch (Exception e) {
context.logger.log(Level.WARNING, "Response.recycleListener error, request = " + request, e);
}
recycleListener = null;
}
this.output = null;
this.filter = null;
this.servlet = null;
request.recycle();
if (channel != null) {
if (keepAlive) {
this.context.runAsync(new PrepareRunner(context, channel, null));
} else {
try {
if (channel.isOpen()) channel.close();
} catch (Exception e) {
}
}
channel.dispose();
channel = null;
}
this.inited = false;
@@ -255,7 +243,27 @@ public abstract class Response<C extends Context, R extends Request<C>> {
if (!this.inited) return; //避免重复关闭
//System.println("耗时: " + (System.currentTimeMillis() - request.createtime));
if (kill) refuseAlive();
this.context.responsePool.accept(this);
if (this.recycleListener != null) {
try {
this.recycleListener.accept(request, this);
} catch (Exception e) {
context.logger.log(Level.WARNING, "Response.recycleListener error, request = " + request, e);
}
this.recycleListener = null;
}
if (request.more) removeChannel();
if (request.keepAlive && !request.more && channel != null) {
if (channel.isOpen()) {
AsyncConnection conn = removeChannel();
this.recycle();
this.prepare();
new PrepareRunner(context, conn, null, this).run();
} else {
channel.dispose();
}
} else {
this.context.responsePool.accept(this);
}
}
public void finish(final byte[] bs) {
@@ -272,24 +280,44 @@ public abstract class Response<C extends Context, R extends Request<C>> {
public void finish(ByteBuffer buffer) {
if (!this.inited) return; //避免重复关闭
this.channel.write(buffer, buffer, finishHandler);
ByteBuffer data = this.request.removeMoredata();
final AsyncConnection conn = this.channel;
final boolean more = data != null && this.request.keepAlive;
this.request.more = more;
conn.write(buffer, buffer, finishHandler);
if (more) new PrepareRunner(this.context, conn, data, null).run();
}
public void finish(boolean kill, ByteBuffer buffer) {
if (!this.inited) return; //避免重复关闭
if (kill) refuseAlive();
this.channel.write(buffer, buffer, finishHandler);
ByteBuffer data = this.request.removeMoredata();
final AsyncConnection conn = this.channel;
final boolean more = data != null && this.request.keepAlive;
this.request.more = more;
conn.write(buffer, buffer, finishHandler);
if (more) new PrepareRunner(this.context, conn, data, null).run();
}
public void finish(ByteBuffer... buffers) {
if (!this.inited) return; //避免重复关闭
this.channel.write(buffers, buffers, finishHandler2);
final AsyncConnection conn = this.channel;
ByteBuffer data = this.request.removeMoredata();
final boolean more = data != null && this.request.keepAlive;
this.request.more = more;
conn.write(buffers, buffers, finishHandler2);
if (more) new PrepareRunner(this.context, conn, data, null).run();
}
public void finish(boolean kill, ByteBuffer... buffers) {
if (!this.inited) return; //避免重复关闭
if (kill) refuseAlive();
this.channel.write(buffers, buffers, finishHandler2);
final AsyncConnection conn = this.channel;
ByteBuffer data = this.request.removeMoredata();
final boolean more = data != null && this.request.keepAlive;
this.request.more = more;
conn.write(buffers, buffers, finishHandler2);
if (more) new PrepareRunner(this.context, conn, data, null).run();
}
protected <A> void send(final ByteBuffer buffer, final A attachment, final CompletionHandler<Integer, A> handler) {

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